From 561a1d64eec8331784527c1594baf5b169c92e7e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 24 Aug 2023 10:19:29 +0200 Subject: [PATCH 001/466] Update plotsquared to v7.0.0 (#2407) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2172a6189..480b8e07c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ griefprevention = "16.18.1" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" towny = "0.99.5.10" -plotsquared = "7.0.0-rc.4" +plotsquared = "7.0.0" # Third party bstats = "3.0.2" From 8efb1aa5334add383ac1ec289325649d4acb60f5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 24 Aug 2023 10:20:09 +0200 Subject: [PATCH 002/466] Update dependency gradle to v8.3 (#2408) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.jar | Bin 63375 -> 63721 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 3 ++- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 033e24c4cdf41af1ab109bc7f253b2b887023340..7f93135c49b765f8051ef9d0a6055ff8e46073d8 100644 GIT binary patch delta 28216 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9f4197d5f..ac72c34e8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index fcb6fca14..0adc8e1a5 100755 --- a/gradlew +++ b/gradlew @@ -83,7 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum From 6f9c3c3e01b16e76299809b7741b9d890b7b5c09 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 24 Aug 2023 10:20:19 +0200 Subject: [PATCH 003/466] Update dependency org.mockito:mockito-core to v5.5.0 (#2409) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- worldedit-sponge/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 480b8e07c..b1d1e61c0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -46,7 +46,7 @@ text = "3.0.4" piston = "0.5.7" # Tests -mockito = "5.4.0" +mockito = "5.5.0" # Gradle plugins pluginyml = "0.6.0" diff --git a/worldedit-sponge/build.gradle.kts b/worldedit-sponge/build.gradle.kts index aba91acea..3c6783886 100644 --- a/worldedit-sponge/build.gradle.kts +++ b/worldedit-sponge/build.gradle.kts @@ -28,7 +28,7 @@ dependencies { }) api("org.apache.logging.log4j:log4j-api") api("org.bstats:bstats-sponge:1.7") - testImplementation("org.mockito:mockito-core:5.4.0") + testImplementation("org.mockito:mockito-core:5.5.0") } <<<<<<< HEAD From 4def201daad9d9ddb26594bb74de6c9c6cce2269 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sat, 26 Aug 2023 17:13:24 +0200 Subject: [PATCH 004/466] Adapt new test methods --- build.gradle.kts | 2 +- .../test/java/com/sk89q/wepif/TestOfflinePermissible.java | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 3f6169bb7..90f33890d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s-%s", rootVersion, buildNumber) +version = String.format("%s", rootVersion) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") diff --git a/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java b/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java index c63e98663..052c772d5 100644 --- a/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java +++ b/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java @@ -144,6 +144,11 @@ public class TestOfflinePermissible implements OfflinePlayer, Permissible { return false; } + @Override + public boolean isConnected() { + return false; + } + @Override public String getName() { return "Tester"; From f5a5eae1a39daef560b7757f68dd6cf07f3a50b7 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sat, 26 Aug 2023 17:34:37 +0200 Subject: [PATCH 005/466] Back to snapshot for development --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 90f33890d..e441c1336 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.7.1") +var rootVersion by extra("2.7.2") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s", rootVersion) +version = String.format("%s-%s", rootVersion, buildNumber) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From 8c611c5324f925647466f77748a721cf0dc040c6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 08:32:13 +0200 Subject: [PATCH 006/466] Update dependency dev.notmyfault.serverlib:ServerLib to v2.3.4 (#2415) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index a6e853eef..4f7211db5 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -174,7 +174,7 @@ tasks.named("shadowJar") { include(dependency("it.unimi.dsi:fastutil")) } relocate("org.incendo.serverlib", "com.fastasyncworldedit.serverlib") { - include(dependency("dev.notmyfault.serverlib:ServerLib:2.3.1")) + include(dependency("dev.notmyfault.serverlib:ServerLib:2.3.4")) } relocate("com.intellectualsites.paster", "com.fastasyncworldedit.paster") { include(dependency("com.intellectualsites.paster:Paster")) From a1ee56569e0f7392718bfbfebff74275a96f97cf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 08:32:34 +0200 Subject: [PATCH 007/466] Update dependency dev.notmyfault.serverlib:ServerLib to v2.3.4 (#2414) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b1d1e61c0..7c13f7c27 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,7 +39,7 @@ commons-cli = "1.5.0" paperlib = "1.0.8" paster = "1.1.5" vault = "1.7.1" -serverlib = "2.3.1" +serverlib = "2.3.4" ## Internal text-adapter = "3.0.6" text = "3.0.4" From 7288393a39e4438731440b2c4e9a4526e123021d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 08:37:58 +0200 Subject: [PATCH 008/466] Update dependency com.palmergames.bukkit.towny:towny to v0.99.5.16 (#2413) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7c13f7c27..74858196d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "16.18.1" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.99.5.10" +towny = "0.99.5.16" plotsquared = "7.0.0" # Third party From 60a3994d628d6d19c2983582fee4a70a35e65398 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sat, 9 Sep 2023 16:07:29 +0200 Subject: [PATCH 009/466] Clean up some regen code (#2405) --- .../v1_17_R1_2/regen/PaperweightRegen.java | 7 +- .../fawe/v1_18_R2/regen/PaperweightRegen.java | 7 +- .../fawe/v1_19_R3/regen/PaperweightRegen.java | 7 +- .../fawe/v1_20_R1/regen/PaperweightRegen.java | 7 +- .../bukkit/adapter/Regenerator.java | 184 +++++++++--------- 5 files changed, 98 insertions(+), 114 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java index 3d9694af9..4d7a749de 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java @@ -184,9 +184,6 @@ public class PaperweightRegen extends Regenerator super.chunkStati.put(new ChunkStatusWrap(s), c)); + chunkStati.forEach((s, c) -> super.chunkStatuses.put(new ChunkStatusWrap(s), c)); return true; } @@ -680,7 +677,7 @@ public class PaperweightRegen extends Regenerator processChunk(Long xz, List accessibleChunks) { + public CompletableFuture processChunk(List accessibleChunks) { return chunkStatus.generate( Runnable::run, // TODO revisit, we might profit from this somehow? freshWorld, diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/regen/PaperweightRegen.java index 51bd22bdb..34e18f748 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/regen/PaperweightRegen.java @@ -178,9 +178,6 @@ public class PaperweightRegen extends Regenerator super.chunkStati.put(new ChunkStatusWrap(s), c)); + chunkStati.forEach((s, c) -> super.chunkStatuses.put(new ChunkStatusWrap(s), c)); return true; } @@ -523,7 +520,7 @@ public class PaperweightRegen extends Regenerator processChunk(Long xz, List accessibleChunks) { + public CompletableFuture processChunk(List accessibleChunks) { return chunkStatus.generate( Runnable::run, // TODO revisit, we might profit from this somehow? freshWorld, diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java index 4f22e8734..22bae54fe 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java @@ -192,9 +192,6 @@ public class PaperweightRegen extends Regenerator super.chunkStati.put(new ChunkStatusWrap(s), c)); + chunkStati.forEach((s, c) -> super.chunkStatuses.put(new ChunkStatusWrap(s), c)); return true; } @@ -554,7 +551,7 @@ public class PaperweightRegen extends Regenerator processChunk(Long xz, List accessibleChunks) { + public CompletableFuture processChunk(List accessibleChunks) { return chunkStatus.generate( Runnable::run, // TODO revisit, we might profit from this somehow? freshWorld, diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java index b5d5a2733..812cf1d4c 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java @@ -192,9 +192,6 @@ public class PaperweightRegen extends Regenerator super.chunkStati.put(new ChunkStatusWrap(s), c)); + chunkStati.forEach((s, c) -> super.chunkStatuses.put(new ChunkStatusWrap(s), c)); return true; } @@ -555,7 +552,7 @@ public class PaperweightRegen extends Regenerator processChunk(Long xz, List accessibleChunks) { + public CompletableFuture processChunk(List accessibleChunks) { return chunkStatus.generate( Runnable::run, // TODO revisit, we might profit from this somehow? freshWorld, diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java index 7c00ebb2b..d0d9bb652 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java @@ -22,14 +22,14 @@ import com.sk89q.worldedit.world.block.BaseBlock; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.longs.LongArrayList; +import it.unimi.dsi.fastutil.longs.LongList; import org.apache.logging.log4j.Logger; -import org.bukkit.World; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.WorldInfo; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; @@ -42,7 +42,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.function.Function; -import java.util.stream.Collectors; /** * Represents an abstract regeneration handler. @@ -62,7 +61,7 @@ public abstract class Regenerator chunkStati = new LinkedHashMap<>(); + protected final Map chunkStatuses = new LinkedHashMap<>(); private final Long2ObjectLinkedOpenHashMap protoChunks = new Long2ObjectLinkedOpenHashMap<>(); private final Long2ObjectOpenHashMap chunks = new Long2ObjectOpenHashMap<>(); protected boolean generateConcurrent = true; @@ -85,19 +84,19 @@ public abstract class Regenerator> chunkCoordsForRadius = new Int2ObjectOpenHashMap<>(); - chunkStati.keySet().stream().map(ChunkStatusWrapper::requiredNeighborChunkRadius0).distinct().forEach(radius -> { + Int2ObjectOpenHashMap chunkCoordsForRadius = new Int2ObjectOpenHashMap<>(); + chunkStatuses.keySet().stream().mapToInt(ChunkStatusWrapper::requiredNeighborChunkRadius0).distinct().forEach(radius -> { if (radius == -1) { //ignore ChunkStatus.EMPTY return; } @@ -186,19 +185,19 @@ public abstract class Regenerator>> worldlimits = new Int2ObjectOpenHashMap<>(); - chunkStati.keySet().stream().map(ChunkStatusWrapper::requiredNeighborChunkRadius0).distinct().forEach(radius -> { + Int2ObjectOpenHashMap>> worldLimits = new Int2ObjectOpenHashMap<>(); + chunkStatuses.keySet().stream().mapToInt(ChunkStatusWrapper::requiredNeighborChunkRadius0).distinct().forEach(radius -> { if (radius == -1) { //ignore ChunkStatus.EMPTY return; } Long2ObjectOpenHashMap> map = new Long2ObjectOpenHashMap<>(); - for (Long xz : chunkCoordsForRadius.get(radius)) { + for (long xz : chunkCoordsForRadius.get(radius)) { int x = MathMan.unpairIntX(xz); int z = MathMan.unpairIntY(xz); List l = new ArrayList<>((radius + 1 + radius) * (radius + 1 + radius)); @@ -209,80 +208,63 @@ public abstract class Regenerator entry : chunkStati.entrySet()) { + for (Map.Entry entry : chunkStatuses.entrySet()) { ChunkStatus chunkStatus = entry.getKey(); int radius = chunkStatus.requiredNeighborChunkRadius0(); - List coords = chunkCoordsForRadius.get(radius); + long[] coords = chunkCoordsForRadius.get(radius); + Long2ObjectOpenHashMap> limitsForRadius = worldLimits.get(radius); if (this.generateConcurrent && entry.getValue() == Concurrency.RADIUS) { - SequentialTasks>> tasks = getChunkStatusTaskRows(coords, radius); - for (ConcurrentTasks> para : tasks) { + SequentialTasks> tasks = getChunkStatusTaskRows(coords, radius); + for (ConcurrentTasks para : tasks) { List scheduled = new ArrayList<>(tasks.size()); - for (SequentialTasks row : para) { + for (LongList row : para) { scheduled.add(() -> { - for (Long xz : row) { - chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz)); + for (long xz : row) { + chunkStatus.processChunkSave(xz, limitsForRadius.get(xz)); } }); } - try { - List> futures = new ArrayList<>(); - scheduled.forEach(task -> futures.add(executor.submit(task))); - for (Future future : futures) { - future.get(); - } - } catch (Exception e) { - e.printStackTrace(); - } + runAndWait(scheduled); } } else if (this.generateConcurrent && entry.getValue() == Concurrency.FULL) { // every chunk can be processed individually - List scheduled = new ArrayList<>(coords.size()); + List scheduled = new ArrayList<>(coords.length); for (long xz : coords) { - scheduled.add(() -> { - chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz)); - }); - } - try { - List> futures = new ArrayList<>(); - scheduled.forEach(task -> futures.add(executor.submit(task))); - for (Future future : futures) { - future.get(); - } - } catch (Exception e) { - e.printStackTrace(); + scheduled.add(() -> chunkStatus.processChunkSave(xz, limitsForRadius.get(xz))); } + runAndWait(scheduled); } else { // Concurrency.NONE or generateConcurrent == false // run sequential but submit to different thread // running regen on the main thread otherwise triggers async-only events on the main thread executor.submit(() -> { for (long xz : coords) { - chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz)); + chunkStatus.processChunkSave(xz, limitsForRadius.get(xz)); } }).get(); // wait until finished this step } } //convert to proper chunks - for (Long xz : chunkCoordsForRadius.get(0)) { + for (long xz : chunkCoordsForRadius.get(0)) { ProtoChunk proto = protoChunks.get(xz); chunks.put(xz, createChunk(proto)); } //final chunkstatus ChunkStatus FULL = getFullChunkStatus(); - for (Long xz : chunkCoordsForRadius.get(0)) { //FULL.requiredNeighbourChunkRadius() == 0! + for (long xz : chunkCoordsForRadius.get(0)) { //FULL.requiredNeighbourChunkRadius() == 0! Chunk chunk = chunks.get(xz); - FULL.processChunkSave(xz, Arrays.asList(chunk)); + FULL.processChunkSave(xz, List.of(chunk)); } //populate List populators = getBlockPopulators(); - for (Long xz : chunkCoordsForRadius.get(0)) { + for (long xz : chunkCoordsForRadius.get(0)) { int x = MathMan.unpairIntX(xz); int z = MathMan.unpairIntY(xz); @@ -302,6 +284,18 @@ public abstract class Regenerator tasks) { + try { + List> futures = new ArrayList<>(); + tasks.forEach(task -> futures.add(executor.submit(task))); + for (Future future : futures) { + future.get(); + } + } catch (Exception e) { + LOGGER.catching(e); + } + } + private void copyToWorld() { //Setting Blocks boolean genbiomes = options.shouldRegenBiomes(); @@ -437,7 +431,7 @@ public abstract class Regenerator initSourceQueueCache(); //algorithms - private List getChunkCoordsRegen(Region region, int border) { //needs to be square num of chunks + private long[] getChunkCoordsRegen(Region region, int border) { //needs to be square num of chunks BlockVector3 oldMin = region.getMinimumPoint(); BlockVector3 newMin = BlockVector3.at( (oldMin.getX() >> 4 << 4) - border * 16, @@ -455,76 +449,79 @@ public abstract class Regenerator MathMan.pairInt(c.getX(), c.getZ())) - .collect(Collectors.toList()); + .mapToLong(c -> MathMan.pairInt(c.getX(), c.getZ())) + .toArray(); } /** * Creates a list of chunkcoord rows that may be executed concurrently * - * @param allcoords the coords that should be sorted into rows, must be sorted by z and x + * @param allCoords the coords that should be sorted into rows, must be sorted by z and x * @param requiredNeighborChunkRadius the radius of neighbor chunks that may not be written to concurrently (ChunkStatus * .requiredNeighborRadius) * @return a list of chunkcoords rows that may be executed concurrently */ - private SequentialTasks>> getChunkStatusTaskRows( - List allcoords, + private SequentialTasks> getChunkStatusTaskRows( + long[] allCoords, int requiredNeighborChunkRadius ) { - int requiredneighbors = Math.max(0, requiredNeighborChunkRadius); + int requiredNeighbors = Math.max(0, requiredNeighborChunkRadius); - int minx = allcoords.isEmpty() ? 0 : MathMan.unpairIntX(allcoords.get(0)); - int maxx = allcoords.isEmpty() ? 0 : MathMan.unpairIntX(allcoords.get(allcoords.size() - 1)); - int minz = allcoords.isEmpty() ? 0 : MathMan.unpairIntY(allcoords.get(0)); - int maxz = allcoords.isEmpty() ? 0 : MathMan.unpairIntY(allcoords.get(allcoords.size() - 1)); - SequentialTasks>> tasks; - if (maxz - minz > maxx - minx) { - int numlists = Math.min(requiredneighbors * 2 + 1, maxx - minx + 1); + final int coordsCount = allCoords.length; + long first = coordsCount == 0 ? 0 : allCoords[0]; + long last = coordsCount == 0 ? 0 : allCoords[coordsCount - 1]; + int minX = MathMan.unpairIntX(first); + int maxX = MathMan.unpairIntX(last); + int minZ = MathMan.unpairIntY(first); + int maxZ = MathMan.unpairIntY(last); + SequentialTasks> tasks; + if (maxZ - minZ > maxX - minX) { + int numlists = Math.min(requiredNeighbors * 2 + 1, maxX - minX + 1); - Int2ObjectOpenHashMap> byx = new Int2ObjectOpenHashMap(); - int expectedListLength = (allcoords.size() + 1) / (maxx - minx); + Int2ObjectOpenHashMap byX = new Int2ObjectOpenHashMap<>(); + int expectedListLength = (coordsCount + 1) / (maxX - minX); //init lists - for (int i = minx; i <= maxx; i++) { - byx.put(i, new SequentialTasks(expectedListLength)); + for (int i = minX; i <= maxX; i++) { + byX.put(i, new LongArrayList(expectedListLength)); } //sort into lists by x coord - for (Long xz : allcoords) { - byx.get(MathMan.unpairIntX(xz)).add(xz); + for (long allCoord : allCoords) { + byX.get(MathMan.unpairIntX(allCoord)).add(allCoord); } //create parallel tasks - tasks = new SequentialTasks(numlists); + tasks = new SequentialTasks<>(numlists); for (int offset = 0; offset < numlists; offset++) { - ConcurrentTasks> para = new ConcurrentTasks((maxz - minz + 1) / numlists + 1); - for (int i = 0; minx + i * numlists + offset <= maxx; i++) { - para.add(byx.get(minx + i * numlists + offset)); + ConcurrentTasks para = new ConcurrentTasks<>((maxZ - minZ + 1) / numlists + 1); + for (int i = 0; minX + i * numlists + offset <= maxX; i++) { + para.add(byX.get(minX + i * numlists + offset)); } tasks.add(para); } } else { - int numlists = Math.min(requiredneighbors * 2 + 1, maxz - minz + 1); + int numlists = Math.min(requiredNeighbors * 2 + 1, maxZ - minZ + 1); - Int2ObjectOpenHashMap> byz = new Int2ObjectOpenHashMap(); - int expectedListLength = (allcoords.size() + 1) / (maxz - minz); + Int2ObjectOpenHashMap byZ = new Int2ObjectOpenHashMap<>(); + int expectedListLength = (coordsCount + 1) / (maxZ - minZ); //init lists - for (int i = minz; i <= maxz; i++) { - byz.put(i, new SequentialTasks(expectedListLength)); + for (int i = minZ; i <= maxZ; i++) { + byZ.put(i, new LongArrayList(expectedListLength)); } //sort into lists by x coord - for (Long xz : allcoords) { - byz.get(MathMan.unpairIntY(xz)).add(xz); + for (long allCoord : allCoords) { + byZ.get(MathMan.unpairIntY(allCoord)).add(allCoord); } //create parallel tasks - tasks = new SequentialTasks(numlists); + tasks = new SequentialTasks<>(numlists); for (int offset = 0; offset < numlists; offset++) { - ConcurrentTasks> para = new ConcurrentTasks((maxx - minx + 1) / numlists + 1); - for (int i = 0; minz + i * numlists + offset <= maxz; i++) { - para.add(byz.get(minz + i * numlists + offset)); + ConcurrentTasks para = new ConcurrentTasks<>((maxX - minX + 1) / numlists + 1); + for (int i = 0; minZ + i * numlists + offset <= maxZ; i++) { + para.add(byZ.get(minZ + i * numlists + offset)); } tasks.add(para); } @@ -576,15 +573,14 @@ public abstract class Regenerator processChunk(Long xz, List accessibleChunks); + public abstract CompletableFuture processChunk(List accessibleChunks); - void processChunkSave(Long xz, List accessibleChunks) { + void processChunkSave(long xz, List accessibleChunks) { try { - processChunk(xz, accessibleChunks).get(); + processChunk(accessibleChunks).get(); } catch (Exception e) { LOGGER.error( "Error while running " + name() + " on chunk " + MathMan.unpairIntX(xz) + "/" + MathMan.unpairIntY(xz), @@ -597,16 +593,16 @@ public abstract class Regenerator extends Tasks { - public SequentialTasks(int expectedsize) { - super(expectedsize); + public SequentialTasks(int expectedSize) { + super(expectedSize); } } public static class ConcurrentTasks extends Tasks { - public ConcurrentTasks(int expectedsize) { - super(expectedsize); + public ConcurrentTasks(int expectedSize) { + super(expectedSize); } } @@ -615,8 +611,8 @@ public abstract class Regenerator tasks; - public Tasks(int expectedsize) { - tasks = new ArrayList(expectedsize); + public Tasks(int expectedSize) { + tasks = new ArrayList<>(expectedSize); } public void add(T task) { From f36c5d42c7f250e11bfd57b06355a22b71eaf7f0 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sat, 9 Sep 2023 16:07:37 +0200 Subject: [PATCH 010/466] Avoid Unsafe usage where possible (#2403) --- .../PaperweightPlatformAdapter.java | 24 +++---------- .../v1_17_R1_2/regen/PaperweightRegen.java | 2 +- .../v1_18_R2/PaperweightPlatformAdapter.java | 35 ++++--------------- .../fawe/v1_18_R2/regen/PaperweightRegen.java | 2 +- .../v1_19_R3/PaperweightPlatformAdapter.java | 34 ++++-------------- .../fawe/v1_19_R3/regen/PaperweightRegen.java | 2 +- .../v1_20_R1/PaperweightPlatformAdapter.java | 34 ++++-------------- .../fawe/v1_20_R1/regen/PaperweightRegen.java | 2 +- .../core/util/ReflectionUtils.java | 19 ++++++++-- 9 files changed, 43 insertions(+), 111 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java index 688a84a14..0854fc7ad 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java @@ -85,11 +85,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final MethodHandle methodGetVisibleChunk; - private static final int CHUNKSECTION_BASE; - private static final int CHUNKSECTION_SHIFT; - private static final Field fieldLock; - private static final long fieldLockOffset; private static final Field fieldGameEventDispatcherSections; private static final MethodHandle methodremoveBlockEntityTicker; @@ -127,15 +123,12 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { getVisibleChunkIfPresent.setAccessible(true); methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent); - Unsafe unsafe = ReflectionUtils.getUnsafe(); if (!PaperLib.isPaper()) { - fieldLock = PalettedContainer.class.getDeclaredField(Refraction.pickName("lock", "m")); - fieldLockOffset = unsafe.objectFieldOffset(fieldLock); + fieldLock.setAccessible(true); } else { // in paper, the used methods are synchronized properly fieldLock = null; - fieldLockOffset = -1; } fieldGameEventDispatcherSections = LevelChunk.class.getDeclaredField(Refraction.pickName( @@ -152,13 +145,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p")); fieldRemove.setAccessible(true); - - CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class); - int scale = unsafe.arrayIndexScale(LevelChunkSection[].class); - if ((scale & (scale - 1)) != 0) { - throw new Error("data type scale not a power of two"); - } - CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale); } catch (RuntimeException e) { throw e; } catch (Throwable rethrow) { @@ -173,9 +159,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { LevelChunkSection value, int layer ) { - long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE; if (layer >= 0 && layer < sections.length) { - return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value); + return ReflectionUtils.compareAndSet(sections, expected, value, layer); } return false; } @@ -190,14 +175,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } try { synchronized (section) { - Unsafe unsafe = ReflectionUtils.getUnsafe(); PalettedContainer blocks = section.getStates(); - Semaphore currentLock = (Semaphore) unsafe.getObject(blocks, fieldLockOffset); + Semaphore currentLock = (Semaphore) fieldLock.get(blocks); if (currentLock instanceof DelegateSemaphore delegateSemaphore) { return delegateSemaphore; } DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); - unsafe.putObject(blocks, fieldLockOffset, newLock); + fieldLock.set(blocks, newLock); return newLock; } } catch (Throwable e) { diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java index 4d7a749de..63d93156b 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java @@ -329,7 +329,7 @@ public class PaperweightRegen extends Regenerator= 0 && layer < sections.length) { - return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value); + return ReflectionUtils.compareAndSet(sections, expected, value, layer); } return false; } @@ -207,19 +188,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } try { synchronized (section) { - Unsafe unsafe = ReflectionUtils.getUnsafe(); PalettedContainer blocks = section.getStates(); - ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject( - blocks, - fieldThreadingDetectorOffset - ); + ThreadingDetector currentThreadingDetector = (ThreadingDetector) fieldThreadingDetector.get(blocks); synchronized (currentThreadingDetector) { - Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset); + Semaphore currentLock = (Semaphore) fieldLock.get(currentThreadingDetector); if (currentLock instanceof DelegateSemaphore delegateSemaphore) { return delegateSemaphore; } DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); - unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock); + fieldLock.set(currentThreadingDetector, newLock); return newLock; } } diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/regen/PaperweightRegen.java index 34e18f748..8403d531d 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/regen/PaperweightRegen.java @@ -342,7 +342,7 @@ public class PaperweightRegen extends Regenerator= 0 && layer < sections.length) { - return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value); + return ReflectionUtils.compareAndSet(sections, expected, value, layer); } return false; } @@ -243,19 +225,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } try { synchronized (section) { - Unsafe unsafe = ReflectionUtils.getUnsafe(); PalettedContainer blocks = section.getStates(); - ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject( - blocks, - fieldThreadingDetectorOffset - ); + ThreadingDetector currentThreadingDetector = (ThreadingDetector) fieldThreadingDetector.get(blocks); synchronized (currentThreadingDetector) { - Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset); + Semaphore currentLock = (Semaphore) fieldLock.get(currentThreadingDetector); if (currentLock instanceof DelegateSemaphore delegateSemaphore) { return delegateSemaphore; } DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); - unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock); + fieldLock.set(currentThreadingDetector, newLock); return newLock; } } diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java index 22bae54fe..7e2f3eaee 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java @@ -369,7 +369,7 @@ public class PaperweightRegen extends Regenerator= 0 && layer < sections.length) { - return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value); + return ReflectionUtils.compareAndSet(sections, expected, value, layer); } return false; } @@ -266,19 +248,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } try { synchronized (section) { - Unsafe unsafe = ReflectionUtils.getUnsafe(); PalettedContainer blocks = section.getStates(); - ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject( - blocks, - fieldThreadingDetectorOffset - ); + ThreadingDetector currentThreadingDetector = (ThreadingDetector) fieldThreadingDetector.get(blocks); synchronized (currentThreadingDetector) { - Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset); + Semaphore currentLock = (Semaphore) fieldLock.get(currentThreadingDetector); if (currentLock instanceof DelegateSemaphore delegateSemaphore) { return delegateSemaphore; } DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); - unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock); + fieldLock.set(currentThreadingDetector, newLock); return newLock; } } diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java index 812cf1d4c..99e001837 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java @@ -370,7 +370,7 @@ public class PaperweightRegen extends Regenerator the type of elements in the array + * @return true if the value at the index was successfully updated to the new value, false otherwise + * @see VarHandle#compareAndSet(Object...) + */ + public static boolean compareAndSet(T[] array, T expectedValue, T newValue, int index) { + return REFERENCE_ARRAY_HANDLE.compareAndSet(array, index, expectedValue, newValue); + } + public static void setAccessibleNonFinal(Field field) { // let's make the field accessible field.setAccessible(true); From 2f309ff22b7e77629f2c3a94193d9d4b64ffa1ea Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 9 Sep 2023 16:08:54 +0200 Subject: [PATCH 011/466] Update dependency org.checkerframework:checker-qual to v3.38.0 (#2416) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 74858196d..d2a63c6ef 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ sparsebitset = "1.2" parallelgzip = "1.0.5" adventure = "4.14.0" adventure-bukkit = "4.3.0" -checkerqual = "3.37.0" +checkerqual = "3.38.0" truezip = "6.8.4" auto-value = "1.10.2" findbugs = "3.0.2" From 0744504fad7d445fd333d5e361933a14b0045184 Mon Sep 17 00:00:00 2001 From: RedstoneFuture Date: Fri, 15 Sep 2023 22:41:28 +0200 Subject: [PATCH 012/466] Adding note about "worldedit.anyblock" permission (#2419) Adding note --- .../java/com/fastasyncworldedit/core/configuration/Settings.java | 1 + 1 file changed, 1 insertion(+) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index 174d59f37..d0aeb5058 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -400,6 +400,7 @@ public class Settings extends Config { "of a waterlogged fence). For blocking/remapping of all occurrences of a property like waterlogged, see", "remap-properties below.", "To generate a blank list, substitute the default content with a set of square brackets [] instead.", + "The 'worldedit.anyblock' permission is not considered here.", "Example block property blocking:", " - \"minecraft:conduit[waterlogged=true]\"", " - \"minecraft:piston[extended=false,facing=west]\"", From 81ba7d1acdea586fa7e515aa6b4b1bcff43aa29c Mon Sep 17 00:00:00 2001 From: Joo200 Date: Thu, 14 Sep 2023 12:07:11 +0200 Subject: [PATCH 013/466] Add worldedit runtime environment to increase yaml alias limit (#2395) This can be set by -Dworldedit.yaml.aliasLimit=XXX in the startup parameter (cherry picked from commit 94565356fd39bf360b35ee77ea5b3614d48be772) --- .../src/main/java/com/sk89q/util/yaml/YAMLProcessor.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/util/yaml/YAMLProcessor.java b/worldedit-core/src/main/java/com/sk89q/util/yaml/YAMLProcessor.java index 146428c3e..f50bd991f 100644 --- a/worldedit-core/src/main/java/com/sk89q/util/yaml/YAMLProcessor.java +++ b/worldedit-core/src/main/java/com/sk89q/util/yaml/YAMLProcessor.java @@ -98,6 +98,8 @@ public class YAMLProcessor extends YAMLNode { LoaderOptions loaderOptions = new LoaderOptions(); try { + int yamlAliasLimit = Integer.getInteger("worldedit.yaml.aliasLimit", 50); + loaderOptions.setMaxAliasesForCollections(yamlAliasLimit); // 64 MB default int yamlCodePointLimit = Integer.getInteger("worldedit.yaml.codePointLimit", 64 * 1024 * 1024); loaderOptions.setCodePointLimit(yamlCodePointLimit); @@ -105,7 +107,7 @@ public class YAMLProcessor extends YAMLNode { // pre-1.32 snakeyaml } - yaml = new Yaml(new SafeConstructor(new LoaderOptions()), representer, dumperOptions, loaderOptions); + yaml = new Yaml(new SafeConstructor(loaderOptions), representer, dumperOptions, loaderOptions); this.file = file; } From 319bc0a5512a97ce65ea39b8f670b4eee30faeea Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sat, 16 Sep 2023 23:44:14 +0200 Subject: [PATCH 014/466] Fix left click on air being ignored and right click on block being handled twice --- .../bukkit/BukkitServerInterface.java | 9 ++ .../worldedit/bukkit/WorldEditListener.java | 85 +++++++++---------- .../extension/platform/AbstractPlatform.java | 5 ++ .../extension/platform/Platform.java | 8 ++ .../internal/event/InteractionDebouncer.java | 69 +++++++++++++++ 5 files changed, 133 insertions(+), 43 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/event/InteractionDebouncer.java diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index 8278142b6..d35ea9a28 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 @@ -42,6 +42,7 @@ import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.lifecycle.Lifecycled; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.registry.Registries; +import io.papermc.lib.PaperLib; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.Server; @@ -258,6 +259,14 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser return SUPPORTED_SIDE_EFFECTS; } + @Override + public long getTickCount() { + if (PaperLib.isPaper()) { + return Bukkit.getCurrentTick(); + } + return super.getTickCount(); + } + public void unregisterCommands() { dynamicCommands.unregisterCommands(); } 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 06f8f81ed..8c9db1c3e 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 @@ -27,6 +27,7 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.event.platform.SessionIdleEvent; import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.event.InteractionDebouncer; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.World; @@ -55,6 +56,7 @@ import java.util.Optional; public class WorldEditListener implements Listener { private final WorldEditPlugin plugin; + private final InteractionDebouncer debouncer; /** * Construct the object. @@ -63,6 +65,7 @@ public class WorldEditListener implements Listener { */ public WorldEditListener(WorldEditPlugin plugin) { this.plugin = plugin; + debouncer = new InteractionDebouncer(plugin.getInternalPlatform()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @@ -128,62 +131,58 @@ public class WorldEditListener implements Listener { */ @EventHandler public void onPlayerInteract(PlayerInteractEvent event) { - if (!plugin.getInternalPlatform().isHookingEvents()) { - return; - } - - if (event.useItemInHand() == Result.DENY) { - return; - } - - if (event.getHand() == EquipmentSlot.OFF_HAND) { + if (!plugin.getInternalPlatform().isHookingEvents() + || event.useItemInHand() == Result.DENY + || event.getHand() == EquipmentSlot.OFF_HAND + || event.getAction() == Action.PHYSICAL) { return; } final Player player = plugin.wrapPlayer(event.getPlayer()); + + if (event.getAction() != Action.LEFT_CLICK_BLOCK) { + Optional previousResult = debouncer.getDuplicateInteractionResult(player); + if (previousResult.isPresent()) { + if (previousResult.get()) { + event.setCancelled(true); + } + return; + } + } + final World world = player.getWorld(); final WorldEdit we = plugin.getWorldEdit(); final Direction direction = BukkitAdapter.adapt(event.getBlockFace()); + final Block clickedBlock = event.getClickedBlock(); + final Location pos = clickedBlock == null ? null : new Location(world, clickedBlock.getX(), clickedBlock.getY(), clickedBlock.getZ()); - Action action = event.getAction(); - if (action == Action.LEFT_CLICK_BLOCK) { - final Block clickedBlock = event.getClickedBlock(); - final Location pos = new Location(world, clickedBlock.getX(), clickedBlock.getY(), clickedBlock.getZ()); - - if (we.handleBlockLeftClick(player, pos, direction)) { - event.setCancelled(true); - } - - if (we.handleArmSwing(player)) { - event.setCancelled(true); - } - - } else if (action == Action.LEFT_CLICK_AIR) { - - if (we.handleArmSwing(player)) { - event.setCancelled(true); - } - - } else if (action == Action.RIGHT_CLICK_BLOCK) { - final Block clickedBlock = event.getClickedBlock(); - final Location pos = new Location(world, clickedBlock.getX(), clickedBlock.getY(), clickedBlock.getZ()); - - if (we.handleBlockRightClick(player, pos, direction)) { - event.setCancelled(true); - } - - if (we.handleRightClick(player)) { - event.setCancelled(true); - } - } else if (action == Action.RIGHT_CLICK_AIR) { - if (we.handleRightClick(player)) { - event.setCancelled(true); - } + boolean result = false; + switch (event.getAction()) { + case LEFT_CLICK_BLOCK: + result = we.handleBlockLeftClick(player, pos, direction) || we.handleArmSwing(player); + break; + case LEFT_CLICK_AIR: + result = we.handleArmSwing(player); + break; + case RIGHT_CLICK_BLOCK: + result = we.handleBlockRightClick(player, pos, direction) || we.handleRightClick(player); + break; + case RIGHT_CLICK_AIR: + result = we.handleRightClick(player); + break; + default: + break; + } + debouncer.setLastInteraction(player, result); + if (result) { + event.setCancelled(true); } } @EventHandler public void onPlayerQuit(PlayerQuitEvent event) { + debouncer.clearInteraction(plugin.wrapPlayer(event.getPlayer())); + plugin.getWorldEdit().getEventBus().post(new SessionIdleEvent(new BukkitPlayer.SessionKeyImpl(event.getPlayer()))); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlatform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlatform.java index 533fe054d..c8f908b4c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlatform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlatform.java @@ -55,4 +55,9 @@ public abstract class AbstractPlatform implements Platform { return null; } + @Override + public long getTickCount() { + return System.nanoTime() / 50_000_000; + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java index 822e7a3f8..f20f3ce9b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java @@ -216,6 +216,14 @@ public interface Platform extends Keyed { */ Set getSupportedSideEffects(); + /** + * Get the number of ticks since the server started. + * On some platforms this value may be an approximation based on the JVM run time. + * + * @return The number of ticks since the server started. + */ + long getTickCount(); + //FAWE start /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/event/InteractionDebouncer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/event/InteractionDebouncer.java new file mode 100644 index 000000000..b33570cd9 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/event/InteractionDebouncer.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 General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.internal.event; + +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.util.Identifiable; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +public class InteractionDebouncer { + private final Platform platform; + private final Map lastInteractions = new HashMap<>(); + + public InteractionDebouncer(Platform platform) { + this.platform = platform; + } + + public void clearInteraction(Identifiable player) { + lastInteractions.remove(player.getUniqueId()); + } + + public void setLastInteraction(Identifiable player, boolean result) { + lastInteractions.put(player.getUniqueId(), new Interaction(platform.getTickCount(), result)); + } + + public Optional getDuplicateInteractionResult(Identifiable player) { + Interaction last = lastInteractions.get(player.getUniqueId()); + if (last == null) { + return Optional.empty(); + } + + long now = platform.getTickCount(); + if (now - last.tick <= 1) { + return Optional.of(last.result); + } + + return Optional.empty(); + } + + private static class Interaction { + public final long tick; + public final boolean result; + + public Interaction(long tick, boolean result) { + this.tick = tick; + this.result = result; + } + } +} From 7b0f1b3c5a64f8aa1096e1d0a9615017bf47e1dd Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sat, 16 Sep 2023 23:47:19 +0200 Subject: [PATCH 015/466] Update paperweight --- worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts index 2f65af4ce..20bff7359 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ - the().paperDevBundle("1.20.1-R0.1-20230818.021330-113") + the().paperDevBundle("1.20.1-R0.1-20230916.212543-167") compileOnly(libs.paperlib) } From 889e9b7185918d16ceb43f19a8a0bdd5ed5bf67a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 12:41:27 +0200 Subject: [PATCH 016/466] Update dependency com.modrinth.minotaur to v2.8.4 (#2429) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d2a63c6ef..b73ec8509 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -50,7 +50,7 @@ mockito = "5.5.0" # Gradle plugins pluginyml = "0.6.0" -minotaur = "2.8.3" +minotaur = "2.8.4" [libraries] # Minecraft expectations From 45b60f4929a3cfb72cbad23934769c596cbb5030 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Fri, 29 Sep 2023 22:00:58 +0200 Subject: [PATCH 017/466] Add support for 1.20.2 (#2431) * Update to 1.20.2 * Update paperweight --------- Co-authored-by: Pierre Maurice Schwang --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- build.gradle.kts | 4 +- gradle/libs.versions.toml | 2 +- settings.gradle.kts | 2 +- .../adapters/adapter-1_20_2/build.gradle.kts | 17 + .../ext/fawe/v1_20_R2/PaperweightAdapter.java | 1022 ++++++ .../v1_20_R2/PaperweightDataConverters.java | 2801 +++++++++++++++++ .../fawe/v1_20_R2/PaperweightFakePlayer.java | 98 + .../PaperweightWorldNativeAccess.java | 181 ++ .../v1_20_R2/PaperweightBlockMaterial.java | 185 ++ .../fawe/v1_20_R2/PaperweightFaweAdapter.java | 652 ++++ .../PaperweightFaweWorldNativeAccess.java | 287 ++ .../fawe/v1_20_R2/PaperweightGetBlocks.java | 1147 +++++++ .../v1_20_R2/PaperweightGetBlocks_Copy.java | 248 ++ .../v1_20_R2/PaperweightMapChunkUtil.java | 34 + .../v1_20_R2/PaperweightPlatformAdapter.java | 719 +++++ .../v1_20_R2/PaperweightPostProcessor.java | 175 + .../PaperweightStarlightRelighter.java | 205 ++ .../PaperweightStarlightRelighterFactory.java | 28 + .../nbt/PaperweightLazyCompoundTag.java | 161 + .../fawe/v1_20_R2/regen/PaperweightRegen.java | 591 ++++ worldedit-bukkit/build.gradle.kts | 2 +- worldedit-core/build.gradle.kts | 2 +- 23 files changed, 8558 insertions(+), 7 deletions(-) create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightDataConverters.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightFakePlayer.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightWorldNativeAccess.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightBlockMaterial.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweWorldNativeAccess.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightMapChunkUtil.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPostProcessor.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighterFactory.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/nbt/PaperweightLazyCompoundTag.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/regen/PaperweightRegen.java diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 8a134b81e..560478e0e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -27,7 +27,7 @@ body: description: Which server version version you using? If your server version is not listed, it is not supported. Update to a supported version first. multiple: false options: - - '1.20.1' + - '1.20.2' - '1.20' - '1.19.4' - '1.18.2' diff --git a/build.gradle.kts b/build.gradle.kts index e441c1336..ed699857f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -83,7 +83,7 @@ allprojects { } applyCommonConfiguration() -val supportedVersions = listOf("1.17.1", "1.18.2", "1.19.4", "1.20", "1.20.1") +val supportedVersions = listOf("1.17.1", "1.18.2", "1.19.4", "1.20", "1.20.2") tasks { supportedVersions.forEach { @@ -97,7 +97,7 @@ tasks { } } runServer { - minecraftVersion("1.20.1") + minecraftVersion("1.20.2") pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile } .toTypedArray()) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b73ec8509..1fe45859b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] # Minecraft expectations -paper = "1.20.1-R0.1-SNAPSHOT" +paper = "1.20.2-R0.1-SNAPSHOT" fastutil = "8.5.9" guava = "31.1-jre" log4j = "2.19.0" diff --git a/settings.gradle.kts b/settings.gradle.kts index 05439cd10..4c6995e2e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,7 +2,7 @@ rootProject.name = "FastAsyncWorldEdit" include("worldedit-libs") -listOf("legacy", "1_17_1", "1_18_2", "1_19_4", "1_20").forEach { +listOf("legacy", "1_17_1", "1_18_2", "1_19_4", "1_20", "1_20_2").forEach { include("worldedit-bukkit:adapters:adapter-$it") } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts new file mode 100644 index 000000000..540d25cca --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts @@ -0,0 +1,17 @@ +import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension + +plugins { + java +} + +applyPaperweightAdapterConfiguration() + +repositories { + gradlePluginPortal() +} + +dependencies { + // https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ + the().paperDevBundle("1.20.2-R0.1-20230929.031919-14") + compileOnly(libs.paperlib) +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java new file mode 100644 index 000000000..38b0701d4 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java @@ -0,0 +1,1022 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Sets; +import com.google.common.util.concurrent.Futures; +import com.mojang.datafixers.util.Either; +import com.mojang.serialization.Lifecycle; +import com.sk89q.jnbt.NBTConstants; +import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R2.PaperweightDataConverters; +import com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2.PaperweightFakePlayer; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extension.platform.Watchdog; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +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.util.SideEffect; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.util.io.file.SafeFiles; +import com.sk89q.worldedit.util.nbt.BinaryTag; +import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; +import com.sk89q.worldedit.util.nbt.ByteBinaryTag; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; +import com.sk89q.worldedit.util.nbt.EndBinaryTag; +import com.sk89q.worldedit.util.nbt.FloatBinaryTag; +import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; +import com.sk89q.worldedit.util.nbt.IntBinaryTag; +import com.sk89q.worldedit.util.nbt.ListBinaryTag; +import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; +import com.sk89q.worldedit.util.nbt.LongBinaryTag; +import com.sk89q.worldedit.util.nbt.ShortBinaryTag; +import com.sk89q.worldedit.util.nbt.StringBinaryTag; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.RegenOptions; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.item.ItemType; +import net.minecraft.Util; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.util.StringRepresentable; +import net.minecraft.util.thread.BlockableEventLoop; +import net.minecraft.world.Clearable; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelSettings; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.StructureBlockEntity; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.WorldOptions; +import net.minecraft.world.level.storage.LevelStorageSource; +import net.minecraft.world.level.storage.PrimaryLevelData; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World.Environment; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_20_R2.CraftServer; +import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_20_R2.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_20_R2.util.CraftMagicNumbers; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; +import org.bukkit.generator.ChunkGenerator; +import org.spigotmc.SpigotConfig; +import org.spigotmc.WatchdogThread; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.OptionalInt; +import java.util.OptionalLong; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +public final class PaperweightAdapter implements BukkitImplAdapter { + + private final Logger logger = Logger.getLogger(getClass().getCanonicalName()); + + private final Field serverWorldsField; + private final Method getChunkFutureMethod; + private final Field chunkProviderExecutorField; + private final Watchdog watchdog; + + // ------------------------------------------------------------------------ + // Code that may break between versions of Minecraft + // ------------------------------------------------------------------------ + + public PaperweightAdapter() throws NoSuchFieldException, NoSuchMethodException { + // A simple test + CraftServer.class.cast(Bukkit.getServer()); + + int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); + if (dataVersion != 3578) { + throw new UnsupportedClassVersionError("Not 1.20.2!"); + } + + serverWorldsField = CraftServer.class.getDeclaredField("worlds"); + serverWorldsField.setAccessible(true); + + getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod( + Refraction.pickName("getChunkFutureMainThread", "c"), + int.class, int.class, ChunkStatus.class, boolean.class + ); + getChunkFutureMethod.setAccessible(true); + + chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField( + Refraction.pickName("mainThreadProcessor", "g") + ); + chunkProviderExecutorField.setAccessible(true); + + new PaperweightDataConverters(CraftMagicNumbers.INSTANCE.getDataVersion(), this).buildUnoptimized(); + + Watchdog watchdog; + try { + Class.forName("org.spigotmc.WatchdogThread"); + watchdog = new SpigotWatchdog(); + } catch (ClassNotFoundException | NoSuchFieldException e) { + try { + watchdog = new MojangWatchdog(((CraftServer) Bukkit.getServer()).getServer()); + } catch (NoSuchFieldException ex) { + watchdog = null; + } + } + this.watchdog = watchdog; + + try { + Class.forName("org.spigotmc.SpigotConfig"); + SpigotConfig.config.set("world-settings.faweregentempworld.verbose", false); + } catch (ClassNotFoundException ignored) { + } + } + + @Override + public DataFixer getDataFixer() { + return PaperweightDataConverters.INSTANCE; + } + + /** + * Read the given NBT data into the given tile entity. + * + * @param tileEntity the tile entity + * @param tag the tag + */ + static void readTagIntoTileEntity(net.minecraft.nbt.CompoundTag tag, BlockEntity tileEntity) { + tileEntity.load(tag); + tileEntity.setChanged(); + } + + /** + * Get the ID string of the given entity. + * + * @param entity the entity + * @return the entity ID + */ + private static String getEntityId(Entity entity) { + return EntityType.getKey(entity.getType()).toString(); + } + + /** + * Create an entity using the given entity ID. + * + * @param id the entity ID + * @param world the world + * @return an entity or null + */ + @Nullable + private static Entity createEntityFromId(String id, net.minecraft.world.level.Level world) { + return EntityType.byString(id).map(t -> t.create(world)).orElse(null); + } + + /** + * Write the given NBT data into the given entity. + * + * @param entity the entity + * @param tag the tag + */ + private static void readTagIntoEntity(net.minecraft.nbt.CompoundTag tag, Entity entity) { + entity.load(tag); + } + + /** + * Write the entity's NBT data to the given tag. + * + * @param entity the entity + * @param tag the tag + */ + private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag tag) { + entity.save(tag); + } + + private static Block getBlockFromType(BlockType blockType) { + + return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK).get(ResourceLocation.tryParse(blockType.getId())); + } + + private static Item getItemFromType(ItemType itemType) { + return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(itemType.getId())); + } + + @Override + public OptionalInt getInternalBlockStateId(BlockData data) { + net.minecraft.world.level.block.state.BlockState state = ((CraftBlockData) data).getState(); + int combinedId = Block.getId(state); + return combinedId == 0 && state.getBlock() != Blocks.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); + } + + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + Block mcBlock = getBlockFromType(state.getBlockType()); + net.minecraft.world.level.block.state.BlockState newState = mcBlock.defaultBlockState(); + Map, Object> states = state.getStates(); + newState = applyProperties(mcBlock.getStateDefinition(), newState, states); + final int combinedId = Block.getId(newState); + return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); + } + + @Override + public BlockState getBlock(Location location) { + checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); + int internalId = Block.getId(blockData); + BlockState state = BlockStateIdAccess.getBlockStateById(internalId); + if (state == null) { + org.bukkit.block.Block bukkitBlock = location.getBlock(); + state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } + + return state; + } + + @Override + public BaseBlock getFullBlock(Location location) { + BlockState state = getBlock(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + + // Read the NBT data + BlockEntity te = chunk.getBlockEntity(blockPos); + if (te != null) { + net.minecraft.nbt.CompoundTag tag = te.saveWithId(); + return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); + } + + return state.toBaseBlock(); + } + + private static final HashMap> biomeTypeToNMSCache = new HashMap<>(); + private static final HashMap, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); + + @Override + public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + return new com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2.PaperweightWorldNativeAccess(this, + new WeakReference<>(((CraftWorld) world).getHandle())); + } + + private static net.minecraft.core.Direction adapt(Direction face) { + switch (face) { + case NORTH: + return net.minecraft.core.Direction.NORTH; + case SOUTH: + return net.minecraft.core.Direction.SOUTH; + case WEST: + return net.minecraft.core.Direction.WEST; + case EAST: + return net.minecraft.core.Direction.EAST; + case DOWN: + return net.minecraft.core.Direction.DOWN; + case UP: + default: + return net.minecraft.core.Direction.UP; + } + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private net.minecraft.world.level.block.state.BlockState applyProperties( + StateDefinition stateContainer, + net.minecraft.world.level.block.state.BlockState newState, + Map, Object> states + ) { + for (Map.Entry, Object> state : states.entrySet()) { + net.minecraft.world.level.block.state.properties.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.world.level.block.state.properties.EnumProperty) { + String enumName = (String) value; + value = ((net.minecraft.world.level.block.state.properties.EnumProperty) property) + .getValue(enumName).orElseThrow(() -> + new IllegalStateException( + "Enum property " + property.getName() + " does not contain " + enumName + ) + ); + } + + newState = newState.setValue( + (net.minecraft.world.level.block.state.properties.Property) property, + (Comparable) value + ); + } + return newState; + } + + @Override + public BaseEntity getEntity(org.bukkit.entity.Entity entity) { + checkNotNull(entity); + + CraftEntity craftEntity = ((CraftEntity) entity); + Entity mcEntity = craftEntity.getHandle(); + + // Do not allow creating of passenger entity snapshots, passengers are included in the vehicle entity + if (mcEntity.isPassenger()) { + return null; + } + + String id = getEntityId(mcEntity); + + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + readEntityIntoTag(mcEntity, tag); + return new BaseEntity( + com.sk89q.worldedit.world.entity.EntityTypes.get(id), + LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag)) + ); + } + + @Nullable + @Override + public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state) { + checkNotNull(location); + checkNotNull(state); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + ServerLevel worldServer = craftWorld.getHandle(); + + Entity createdEntity = createEntityFromId(state.getType().getId(), craftWorld.getHandle()); + + if (createdEntity != null) { + CompoundBinaryTag nativeTag = state.getNbt(); + if (nativeTag != null) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(nativeTag); + for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + readTagIntoEntity(tag, createdEntity); + } + + createdEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + + worldServer.addFreshEntity(createdEntity, SpawnReason.CUSTOM); + return createdEntity.getBukkitEntity(); + } else { + return null; + } + } + + // This removes all unwanted tags from the main entity and all its passengers + private void removeUnwantedEntityTagsRecursively(net.minecraft.nbt.CompoundTag tag) { + for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + + // Adapted from net.minecraft.world.entity.EntityType#loadEntityRecursive + if (tag.contains("Passengers", NBTConstants.TYPE_LIST)) { + net.minecraft.nbt.ListTag nbttaglist = tag.getList("Passengers", NBTConstants.TYPE_COMPOUND); + + for (int i = 0; i < nbttaglist.size(); ++i) { + removeUnwantedEntityTagsRecursively(nbttaglist.getCompound(i)); + } + } + } + + @Override + public Component getRichBlockName(BlockType blockType) { + return TranslatableComponent.of(getBlockFromType(blockType).getDescriptionId()); + } + + @Override + public Component getRichItemName(ItemType itemType) { + return TranslatableComponent.of(getItemFromType(itemType).getDescriptionId()); + } + + @Override + public Component getRichItemName(BaseItemStack itemStack) { + return TranslatableComponent.of(CraftItemStack.asNMSCopy(BukkitAdapter.adapt(itemStack)).getDescriptionId()); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static final LoadingCache> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { + @Override + public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { + if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else if (state instanceof DirectionProperty) { + return new DirectionalProperty(state.getName(), + (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); + } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + return new EnumProperty(state.getName(), + (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); + } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else { + throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); + } + } + }); + + @SuppressWarnings({ "rawtypes" }) + @Override + public Map> getProperties(BlockType blockType) { + Map> properties = new TreeMap<>(); + Block block = getBlockFromType(blockType); + StateDefinition blockStateList = + block.getStateDefinition(); + for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { + Property property = PROPERTY_CACHE.getUnchecked(state); + properties.put(property.getName(), property); + } + return properties; + } + + @Override + public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { + ((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create( + new StructureBlockEntity( + new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()), + Blocks.STRUCTURE_BLOCK.defaultBlockState() + ), + __ -> (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) + )); + } + + @Override + public void sendFakeOP(Player player) { + ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( + ((CraftPlayer) player).getHandle(), (byte) 28 + )); + } + + @Override + public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { + ItemStack stack = new ItemStack( + DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().getId())), + item.getAmount() + ); + stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData()))); + return CraftItemStack.asCraftMirror(stack); + } + + @Override + public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { + final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); + final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); + weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); + return weStack; + } + + private final LoadingCache fakePlayers + = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); + + @Override + public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) { + CraftWorld craftWorld = (CraftWorld) world; + ServerLevel worldServer = craftWorld.getHandle(); + ItemStack stack = CraftItemStack.asNMSCopy(BukkitAdapter.adapt(item instanceof BaseItemStack + ? ((BaseItemStack) item) : new BaseItemStack(item.getType(), item.getNbtData(), 1))); + stack.setTag((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData())); + + PaperweightFakePlayer fakePlayer; + try { + fakePlayer = fakePlayers.get(worldServer); + } catch (ExecutionException ignored) { + return false; + } + fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); + fakePlayer.absMoveTo(position.getBlockX(), position.getBlockY(), position.getBlockZ(), + (float) face.toVector().toYaw(), (float) face.toVector().toPitch()); + + final BlockPos blockPos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos); + final net.minecraft.core.Direction enumFacing = adapt(face); + BlockHitResult rayTrace = new BlockHitResult(blockVec, enumFacing, blockPos, false); + UseOnContext context = new UseOnContext(fakePlayer, InteractionHand.MAIN_HAND, rayTrace); + InteractionResult result = stack.useOn(context); + if (result != InteractionResult.SUCCESS) { + if (worldServer.getBlockState(blockPos).use(worldServer, fakePlayer, InteractionHand.MAIN_HAND, rayTrace).consumesAction()) { + result = InteractionResult.SUCCESS; + } else { + result = stack.getItem().use(worldServer, fakePlayer, InteractionHand.MAIN_HAND).getResult(); + } + } + + return result == InteractionResult.SUCCESS; + } + + @Override + public boolean canPlaceAt(org.bukkit.World world, BlockVector3 position, BlockState blockState) { + int internalId = BlockStateIdAccess.getBlockStateId(blockState); + net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId); + return blockData.canSurvive(((CraftWorld) world).getHandle(), new BlockPos(position.getX(), position.getY(), position.getZ())); + } + + @Override + public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) { + try { + doRegen(bukkitWorld, region, extent, options); + } catch (Exception e) { + throw new IllegalStateException("Regen failed.", e); + } + + return true; + } + + private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { + Environment env = bukkitWorld.getEnvironment(); + ChunkGenerator gen = bukkitWorld.getGenerator(); + + Path tempDir = Files.createTempDirectory("WorldEditWorldGen"); + LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir); + ResourceKey worldDimKey = getWorldDimKey(env); + try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { + ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); + PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() + .getWorldData().overworldData(); + WorldOptions originalOpts = levelProperties.worldGenOptions(); + + long seed = options.getSeed().orElse(originalWorld.getSeed()); + WorldOptions newOpts = options.getSeed().isPresent() + ? originalOpts.withSeed(OptionalLong.of(seed)) + : originalOpts; + + LevelSettings newWorldSettings = new LevelSettings( + "faweregentempworld", + levelProperties.settings.gameType(), + levelProperties.settings.hardcore(), + levelProperties.settings.difficulty(), + levelProperties.settings.allowCommands(), + levelProperties.settings.gameRules(), + levelProperties.settings.getDataConfiguration() + ); + + PrimaryLevelData.SpecialWorldProperty specialWorldProperty = + levelProperties.isFlatWorld() + ? PrimaryLevelData.SpecialWorldProperty.FLAT + : levelProperties.isDebugWorld() + ? PrimaryLevelData.SpecialWorldProperty.DEBUG + : PrimaryLevelData.SpecialWorldProperty.NONE; + + PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable()); + + ServerLevel freshWorld = new ServerLevel( + originalWorld.getServer(), + originalWorld.getServer().executor, + session, newWorldData, + originalWorld.dimension(), + new LevelStem( + originalWorld.dimensionTypeRegistration(), + originalWorld.getChunkSource().getGenerator() + ), + new NoOpWorldLoadListener(), + originalWorld.isDebug(), + seed, + ImmutableList.of(), + false, + originalWorld.getRandomSequences(), + env, + gen, + bukkitWorld.getBiomeProvider() + ); + try { + regenForWorld(region, extent, freshWorld, options); + } finally { + freshWorld.getChunkSource().close(false); + } + } finally { + try { + @SuppressWarnings("unchecked") + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); + map.remove("faweregentempworld"); + } catch (IllegalAccessException ignored) { + } + SafeFiles.tryHardToDeleteDir(tempDir); + } + } + + private BiomeType adapt(ServerLevel serverWorld, Biome origBiome) { + ResourceLocation key = serverWorld.registryAccess().registryOrThrow(Registries.BIOME).getKey(origBiome); + if (key == null) { + return null; + } + return BiomeTypes.get(key.toString()); + } + + @SuppressWarnings("unchecked") + private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld, RegenOptions options) throws WorldEditException { + List> chunkLoadings = submitChunkLoadTasks(region, serverWorld); + BlockableEventLoop executor; + try { + executor = (BlockableEventLoop) chunkProviderExecutorField.get(serverWorld.getChunkSource()); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Couldn't get executor for chunk loading.", e); + } + executor.managedBlock(() -> { + // bail out early if a future fails + if (chunkLoadings.stream().anyMatch(ftr -> + ftr.isDone() && Futures.getUnchecked(ftr) == null + )) { + return false; + } + return chunkLoadings.stream().allMatch(CompletableFuture::isDone); + }); + Map chunks = new HashMap<>(); + for (CompletableFuture future : chunkLoadings) { + @Nullable + ChunkAccess chunk = future.getNow(null); + checkState(chunk != null, "Failed to generate a chunk, regen failed."); + chunks.put(chunk.getPos(), chunk); + } + + for (BlockVector3 vec : region) { + BlockPos pos = new BlockPos(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()); + ChunkAccess chunk = chunks.get(new ChunkPos(pos)); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(pos); + int internalId = Block.getId(blockData); + BlockStateHolder state = BlockStateIdAccess.getBlockStateById(internalId); + Objects.requireNonNull(state); + BlockEntity blockEntity = chunk.getBlockEntity(pos); + if (blockEntity != null) { + net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); + state = state.toBaseBlock(((CompoundBinaryTag) toNativeBinary(tag))); + } + extent.setBlock(vec, state.toBaseBlock()); + if (options.shouldRegenBiomes()) { + Biome origBiome = chunk.getNoiseBiome(vec.getX(), vec.getY(), vec.getZ()).value(); + BiomeType adaptedBiome = adapt(serverWorld, origBiome); + if (adaptedBiome != null) { + extent.setBiome(vec, adaptedBiome); + } + } + } + } + + @SuppressWarnings("unchecked") + private List> submitChunkLoadTasks(Region region, ServerLevel serverWorld) { + ServerChunkCache chunkManager = serverWorld.getChunkSource(); + List> chunkLoadings = new ArrayList<>(); + // Pre-gen all the chunks + for (BlockVector2 chunk : region.getChunks()) { + try { + //noinspection unchecked + chunkLoadings.add( + ((CompletableFuture>) + getChunkFutureMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) + .thenApply(either -> either.left().orElse(null)) + ); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException("Couldn't load chunk for regen.", e); + } + } + return chunkLoadings; + } + + private ResourceKey getWorldDimKey(Environment env) { + switch (env) { + case NETHER: + return LevelStem.NETHER; + case THE_END: + return LevelStem.END; + case NORMAL: + default: + return LevelStem.OVERWORLD; + } + } + + private static final Set SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( + SideEffect.NEIGHBORS, + SideEffect.LIGHTING, + SideEffect.VALIDATION, + SideEffect.ENTITY_AI, + SideEffect.EVENTS, + SideEffect.UPDATE + ); + + @Override + public Set getSupportedSideEffects() { + return SUPPORTED_SIDE_EFFECTS; + } + + @Override + public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + + BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + if (entity instanceof Clearable) { + ((Clearable) entity).clearContent(); + return true; + } + return false; + } + + // ------------------------------------------------------------------------ + // Code that is less likely to break + // ------------------------------------------------------------------------ + + /** + * Converts from a non-native NMS NBT structure to a native WorldEdit NBT + * structure. + * + * @param foreign non-native NMS NBT structure + * @return native WorldEdit NBT structure + */ + @Override + public BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { + if (foreign == null) { + return null; + } + if (foreign instanceof net.minecraft.nbt.CompoundTag) { + Map values = new HashMap<>(); + Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); + + for (String str : foreignKeys) { + net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); + values.put(str, toNativeBinary(base)); + } + return CompoundBinaryTag.from(values); + } else if (foreign instanceof net.minecraft.nbt.ByteTag) { + return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); + } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { + return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); + } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { + return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); + } else if (foreign instanceof net.minecraft.nbt.FloatTag) { + return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); + } else if (foreign instanceof net.minecraft.nbt.IntTag) { + return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); + } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { + return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); + } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { + return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); + } else if (foreign instanceof net.minecraft.nbt.ListTag) { + try { + return toNativeList((net.minecraft.nbt.ListTag) foreign); + } catch (Throwable e) { + logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); + return ListBinaryTag.empty(); + } + } else if (foreign instanceof net.minecraft.nbt.LongTag) { + return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); + } else if (foreign instanceof net.minecraft.nbt.ShortTag) { + return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); + } else if (foreign instanceof net.minecraft.nbt.StringTag) { + return StringBinaryTag.of(foreign.getAsString()); + } else if (foreign instanceof net.minecraft.nbt.EndTag) { + return EndBinaryTag.get(); + } else { + throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); + } + } + + /** + * Convert a foreign NBT list tag into a native WorldEdit one. + * + * @param foreign the foreign tag + * @return the converted tag + * @throws SecurityException on error + * @throws IllegalArgumentException on error + */ + private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { + ListBinaryTag.Builder values = ListBinaryTag.builder(); + + for (net.minecraft.nbt.Tag tag : foreign) { + values.add(toNativeBinary(tag)); + } + + return values.build(); + } + + /** + * Converts a WorldEdit-native NBT structure to a NMS structure. + * + * @param foreign structure to convert + * @return non-native structure + */ + @Override + public net.minecraft.nbt.Tag fromNativeBinary(BinaryTag foreign) { + if (foreign == null) { + return null; + } + if (foreign instanceof CompoundBinaryTag) { + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + for (String key : ((CompoundBinaryTag) foreign).keySet()) { + tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); + } + return tag; + } else if (foreign instanceof ByteBinaryTag) { + return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); + } else if (foreign instanceof ByteArrayBinaryTag) { + return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); + } else if (foreign instanceof DoubleBinaryTag) { + return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); + } else if (foreign instanceof FloatBinaryTag) { + return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); + } else if (foreign instanceof IntBinaryTag) { + return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); + } else if (foreign instanceof IntArrayBinaryTag) { + return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); + } else if (foreign instanceof LongArrayBinaryTag) { + return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); + } else if (foreign instanceof ListBinaryTag) { + net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); + ListBinaryTag foreignList = (ListBinaryTag) foreign; + for (BinaryTag t : foreignList) { + tag.add(fromNativeBinary(t)); + } + return tag; + } else if (foreign instanceof LongBinaryTag) { + return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); + } else if (foreign instanceof ShortBinaryTag) { + return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); + } else if (foreign instanceof StringBinaryTag) { + return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); + } else if (foreign instanceof EndBinaryTag) { + return net.minecraft.nbt.EndTag.INSTANCE; + } else { + throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); + } + } + + @Override + public boolean supportsWatchdog() { + return watchdog != null; + } + + @Override + public void tickWatchdog() { + watchdog.tick(); + } + + private class SpigotWatchdog implements Watchdog { + private final Field instanceField; + private final Field lastTickField; + + SpigotWatchdog() throws NoSuchFieldException { + Field instanceField = WatchdogThread.class.getDeclaredField("instance"); + instanceField.setAccessible(true); + this.instanceField = instanceField; + + Field lastTickField = WatchdogThread.class.getDeclaredField("lastTick"); + lastTickField.setAccessible(true); + this.lastTickField = lastTickField; + } + + @Override + public void tick() { + try { + WatchdogThread instance = (WatchdogThread) this.instanceField.get(null); + if ((long) lastTickField.get(instance) != 0) { + WatchdogThread.tick(); + } + } catch (IllegalAccessException e) { + logger.log(Level.WARNING, "Failed to tick watchdog", e); + } + } + } + + private static class MojangWatchdog implements Watchdog { + private final DedicatedServer server; + private final Field tickField; + + MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { + this.server = server; + Field tickField = MinecraftServer.class.getDeclaredField( + Refraction.pickName("nextTickTime", "ah") + ); + if (tickField.getType() != long.class) { + throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); + } + tickField.setAccessible(true); + this.tickField = tickField; + } + + @Override + public void tick() { + try { + tickField.set(server, Util.getMillis()); + } catch (IllegalAccessException ignored) { + } + } + } + + private static class NoOpWorldLoadListener implements ChunkProgressListener { + @Override + public void updateSpawnPos(ChunkPos spawnPos) { + } + + @Override + public void onStatusChange(ChunkPos pos, @org.jetbrains.annotations.Nullable ChunkStatus status) { + } + + @Override + public void start() { + } + + @Override + public void stop() { + } + + @Override + public void setChunkRadius(int radius) { + } + } +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightDataConverters.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightDataConverters.java new file mode 100644 index 000000000..af49e2809 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightDataConverters.java @@ -0,0 +1,2801 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R2; + +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; +import com.mojang.datafixers.DSL.TypeReference; +import com.mojang.datafixers.DataFixer; +import com.mojang.datafixers.DataFixerBuilder; +import com.mojang.datafixers.schemas.Schema; +import com.mojang.serialization.Dynamic; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import net.minecraft.core.Direction; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import net.minecraft.util.StringUtil; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.world.item.DyeColor; +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({ "rawtypes", "unchecked" }) +public class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { + + //FAWE start - BinaryTag + @SuppressWarnings("unchecked") + @Override + public T fixUp(FixType type, T original, int srcVer) { + if (type == FixTypes.CHUNK) { + return (T) fixChunk((CompoundBinaryTag) original, srcVer); + } else if (type == FixTypes.BLOCK_ENTITY) { + return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); + } else if (type == FixTypes.ENTITY) { + return (T) fixEntity((CompoundBinaryTag) 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 CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); + net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); + return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + } + + private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); + net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); + return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + } + + private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); + net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); + return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + } + //FAWE end + + 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(References.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.contains("Properties", 10)) { + sb.append('['); + net.minecraft.nbt.CompoundTag props = tagCompound.getCompound("Properties"); + sb.append(props.getAllKeys().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, References.BIOME); + } + + private String fixItemType(String key, int srcVer) { + return fixName(key, srcVer, References.ITEM_NAME); + } + + private static String fixName(String key, int srcVer, TypeReference type) { + return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, net.minecraft.nbt.StringTag.valueOf(key)), srcVer, DATA_VERSION) + .getValue().getAsString(); + } + + private final com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2.PaperweightAdapter adapter; + + private static final NbtOps OPS_NBT = NbtOps.INSTANCE; + private static final int LEGACY_VERSION = 1343; + private static int DATA_VERSION; + public static PaperweightDataConverters 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(References.LEVEL), + PLAYER(References.PLAYER), + CHUNK(References.CHUNK), + BLOCK_ENTITY(References.BLOCK_ENTITY), + ENTITY(References.ENTITY), + ITEM_INSTANCE(References.ITEM_STACK), + OPTIONS(References.OPTIONS), + STRUCTURE(References.STRUCTURE); + + private final TypeReference type; + + LegacyType(TypeReference type) { + this.type = type; + DFU_TO_LEGACY.put(type.typeName(), this); + } + + public TypeReference getDFUType() { + return type; + } + } + + public PaperweightDataConverters(int dataVersion, + com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2.PaperweightAdapter adapter) { + super(dataVersion); + DATA_VERSION = dataVersion; + INSTANCE = this; + this.adapter = adapter; + registerConverters(); + registerInspectors(); + } + + + // Called after fixers are built and ready for FIXING + @Override + public DataFixer buildUnoptimized() { + return this.fixer = new WrappedDataFixer(DataFixers.getDataFixer()); + } + + @Override + public DataFixer buildOptimized(final Set requiredTypes, Executor executor) { + return buildUnoptimized(); + } + + @SuppressWarnings("unchecked") + 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 = PaperweightDataConverters.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 = PaperweightDataConverters.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.contains("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 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, 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.contains(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.contains(key, 9)) { + net.minecraft.nbt.ListTag nbttaglist = nbttagcompound.getList(key, 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set(j, convert(LegacyType.ITEM_INSTANCE, nbttaglist.getCompound(j), sourceVer, targetVer)); + } + } + + } + + private static class DataConverterEquipment implements DataConverter { + + DataConverterEquipment() { + } + + public int getDataVersion() { + return 100; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + net.minecraft.nbt.ListTag nbttaglist = cmp.getList("Equipment", 10); + net.minecraft.nbt.ListTag nbttaglist1; + + if (!nbttaglist.isEmpty() && !cmp.contains("HandItems", 10)) { + nbttaglist1 = new net.minecraft.nbt.ListTag(); + nbttaglist1.add(nbttaglist.get(0)); + nbttaglist1.add(new net.minecraft.nbt.CompoundTag()); + cmp.put("HandItems", nbttaglist1); + } + + if (nbttaglist.size() > 1 && !cmp.contains("ArmorItem", 10)) { + nbttaglist1 = new net.minecraft.nbt.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.contains("DropChances", 9)) { + nbttaglist1 = cmp.getList("DropChances", 5); + net.minecraft.nbt.ListTag nbttaglist2; + + if (!cmp.contains("HandDropChances", 10)) { + nbttaglist2 = new net.minecraft.nbt.ListTag(); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(0))); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(0.0F)); + cmp.put("HandDropChances", nbttaglist2); + } + + if (!cmp.contains("ArmorDropChances", 10)) { + nbttaglist2 = new net.minecraft.nbt.ListTag(); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(1))); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(2))); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(3))); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(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); + } + } + + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (!cmp.contains("tag", 10)) { + return cmp; + } else { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("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.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 { + + DataInspectorEntity() { + } + + 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.contains("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; + + 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (this.key.equals(new ResourceLocation(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) { + PaperweightDataConverters.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) { + PaperweightDataConverters.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.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"; + // Paper start + materials[409] = "minecraft:prismarine_shard"; + materials[410] = "minecraft:prismarine_crystals"; + materials[411] = "minecraft:rabbit"; + materials[412] = "minecraft:cooked_rabbit"; + materials[413] = "minecraft:rabbit_stew"; + materials[414] = "minecraft:rabbit_foot"; + materials[415] = "minecraft:rabbit_hide"; + materials[416] = "minecraft:armor_stand"; + materials[423] = "minecraft:mutton"; + materials[424] = "minecraft:cooked_mutton"; + materials[425] = "minecraft:banner"; + materials[426] = "minecraft:end_crystal"; + materials[427] = "minecraft:spruce_door"; + materials[428] = "minecraft:birch_door"; + materials[429] = "minecraft:jungle_door"; + materials[430] = "minecraft:acacia_door"; + materials[431] = "minecraft:dark_oak_door"; + materials[432] = "minecraft:chorus_fruit"; + materials[433] = "minecraft:chorus_fruit_popped"; + materials[434] = "minecraft:beetroot"; + materials[435] = "minecraft:beetroot_seeds"; + materials[436] = "minecraft:beetroot_soup"; + materials[437] = "minecraft:dragon_breath"; + materials[438] = "minecraft:splash_potion"; + materials[439] = "minecraft:spectral_arrow"; + materials[440] = "minecraft:tipped_arrow"; + materials[441] = "minecraft:lingering_potion"; + materials[442] = "minecraft:shield"; + materials[443] = "minecraft:elytra"; + materials[444] = "minecraft:spruce_boat"; + materials[445] = "minecraft:birch_boat"; + materials[446] = "minecraft:jungle_boat"; + materials[447] = "minecraft:acacia_boat"; + materials[448] = "minecraft:dark_oak_boat"; + materials[449] = "minecraft:totem_of_undying"; + materials[450] = "minecraft:shulker_shell"; + materials[452] = "minecraft:iron_nugget"; + materials[453] = "minecraft:knowledge_book"; + // Paper end + } + } + + 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.contains("tag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + + if (nbttagcompound2.contains("Base", 99)) { + cmp.putShort("Damage", (short) (nbttagcompound2.getShort("Base") & 15)); + if (nbttagcompound1.contains("display", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound3 = nbttagcompound1.getCompound("display"); + + if (nbttagcompound3.contains("Lore", 9)) { + net.minecraft.nbt.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.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 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.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("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.contains("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.contains("SpawnPotentials", 9)) { + net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int i = 0; i < nbttaglist.size(); ++i) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist.getCompound(i); + + if (nbttagcompound2.contains("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.contains("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.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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("EntityHorse".equals(cmp.getString("id")) && !cmp.contains("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.contains("Facing", 99)) { + Direction enumdirection; + + if (cmp.contains("Direction", 99)) { + enumdirection = Direction.from2DDataValue(cmp.getByte("Direction")); + cmp.putInt("TileX", cmp.getInt("TileX") + enumdirection.getStepX()); + cmp.putInt("TileY", cmp.getInt("TileY") + enumdirection.getStepY()); + cmp.putInt("TileZ", cmp.getInt("TileZ") + enumdirection.getStepZ()); + cmp.remove("Direction"); + if (flag1 && cmp.contains("ItemRotation", 99)) { + cmp.putByte("ItemRotation", (byte) (cmp.getByte("ItemRotation") * 2)); + } + } else { + enumdirection = Direction.from2DDataValue(cmp.getByte("Dir")); + cmp.remove("Dir"); + } + + cmp.putByte("Facing", (byte) enumdirection.get2DDataValue()); + } + + 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) { + net.minecraft.nbt.ListTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + while (cmp.contains("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) { + net.minecraft.nbt.ListTag nbttaglist = new net.minecraft.nbt.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.contains("pages", 9)) { + net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("pages", 8); + + for (int i = 0; i < nbttaglist.size(); ++i) { + String s = nbttaglist.getString(i); + Component object = null; + + if (!"null".equals(s) && !StringUtil.isNullOrEmpty(s)) { + if ((s.charAt(0) != 34 || s.charAt(s.length() - 1) != 34) && (s.charAt(0) != 123 || s.charAt(s.length() - 1) != 125)) { + object = Component.literal(s); + } else { + try { + object = GsonHelper.fromJson(DataConverterSignText.a, s, Component.class, true); + if (object == null) { + object = Component.literal(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = Component.Serializer.fromJson(s); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = Component.Serializer.fromJsonLenient(s); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = Component.literal(s); + } + } + } else { + object = Component.literal(""); + } + + nbttaglist.set(i, net.minecraft.nbt.StringTag.valueOf(Component.Serializer.toJson(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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 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 0: + default: + break; + + 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"); + } + + 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 0: + default: + cmp.putString("id", "Horse"); + break; + + 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"); + } + + 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.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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:shulker_box".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("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.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 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(PaperweightDataConverters.class); + + DataConverterBedBlock() { + } + + public int getDataVersion() { + return 1125; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + try { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); + int i = nbttagcompound1.getInt("xPos"); + int j = nbttagcompound1.getInt("zPos"); + net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("TileEntities", 10); + net.minecraft.nbt.ListTag nbttaglist1 = nbttagcompound1.getList("Sections", 10); + + for (int k = 0; k < nbttaglist1.size(); ++k) { + net.minecraft.nbt.CompoundTag 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; + net.minecraft.nbt.CompoundTag nbttagcompound3 = new net.minecraft.nbt.CompoundTag(); + + nbttagcompound3.putString("id", "bed"); + nbttagcompound3.putInt("x", i1 + (i << 4)); + nbttagcompound3.putInt("y", j1 + (b0 << 4)); + nbttagcompound3.putInt("z", k1 + (j << 4)); + nbttaglist.add(nbttagcompound3); + } + } + } + } catch (Exception exception) { + DataConverterBedBlock.a.warn("Unable to datafix Bed blocks, level format may be missing tags."); + } + + return cmp; + } + } + + private static class DataConverterBedItem implements DataConverter { + + DataConverterBedItem() { + } + + public int getDataVersion() { + return 1125; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:bed".equals(cmp.getString("id")) && cmp.getShort("Damage") == 0) { + cmp.putShort("Damage", (short) DyeColor.RED.getId()); + } + + return cmp; + } + } + + private static class DataConverterSignText implements DataConverter { + + public static final Gson a = new GsonBuilder().registerTypeAdapter(Component.class, new JsonDeserializer() { + MutableComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { + if (jsonelement.isJsonPrimitive()) { + return Component.literal(jsonelement.getAsString()); + } else if (jsonelement.isJsonArray()) { + JsonArray jsonarray = jsonelement.getAsJsonArray(); + MutableComponent ichatbasecomponent = null; + Iterator iterator = jsonarray.iterator(); + + while (iterator.hasNext()) { + JsonElement jsonelement1 = (JsonElement) iterator.next(); + MutableComponent ichatbasecomponent1 = this.a(jsonelement1, jsonelement1.getClass(), jsondeserializationcontext); + + if (ichatbasecomponent == null) { + ichatbasecomponent = ichatbasecomponent1; + } else { + ichatbasecomponent.append(ichatbasecomponent1); + } + } + + return ichatbasecomponent; + } 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); + Component object = null; + + if (!"null".equals(s1) && !StringUtil.isNullOrEmpty(s1)) { + if ((s1.charAt(0) != 34 || s1.charAt(s1.length() - 1) != 34) && (s1.charAt(0) != 123 || s1.charAt(s1.length() - 1) != 125)) { + object = Component.literal(s1); + } else { + try { + object = GsonHelper.fromJson(DataConverterSignText.a, s1, Component.class, true); + if (object == null) { + object = Component.literal(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = Component.Serializer.fromJson(s1); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = Component.Serializer.fromJsonLenient(s1); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = Component.literal(s1); + } + } + } else { + object = Component.literal(""); + } + + nbttagcompound.putString(s, Component.Serializer.toJson(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.contains("RootVehicle", 10)) { + net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + net.minecraft.nbt.ListTag nbttaglist; + int j; + net.minecraft.nbt.CompoundTag nbttagcompound1; + + if (cmp.contains("entities", 9)) { + nbttaglist = cmp.getList("entities", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttagcompound1 = (net.minecraft.nbt.CompoundTag) 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 = (net.minecraft.nbt.CompoundTag) 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.contains("Level", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); + net.minecraft.nbt.ListTag 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, (net.minecraft.nbt.CompoundTag) 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, (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.contains("Passengers", 9)) { + net.minecraft.nbt.ListTag 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 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.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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (entityVillager.equals(new ResourceLocation(cmp.getString("id"))) && cmp.contains("Offers", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Offers"); + + if (nbttagcompound1.contains("Recipes", 9)) { + net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("Recipes", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (tileEntityMobSpawner.equals(new ResourceLocation(cmp.getString("id")))) { + if (cmp.contains("SpawnPotentials", 9)) { + net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightFakePlayer.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightFakePlayer.java new file mode 100644 index 000000000..f05eebe0c --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightFakePlayer.java @@ -0,0 +1,98 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2; + +import com.mojang.authlib.GameProfile; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.stats.Stat; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.player.ChatVisiblity; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.phys.Vec3; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + +import java.util.OptionalInt; +import java.util.UUID; + +class PaperweightFakePlayer extends ServerPlayer { + private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]"); + private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D); + private static final ClientInformation FAKE_CLIENT_INFO = new ClientInformation( + "en_US", 16, ChatVisiblity.FULL, true, 0, HumanoidArm.LEFT, false, false + ); + + PaperweightFakePlayer(ServerLevel world) { + super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE, FAKE_CLIENT_INFO); + } + + @Override + public Vec3 position() { + return ORIGIN; + } + + @Override + public void tick() { + } + + @Override + public void die(DamageSource damagesource) { + } + + @Override + public Entity changeDimension(ServerLevel worldserver, TeleportCause cause) { + return this; + } + + @Override + public OptionalInt openMenu(MenuProvider factory) { + return OptionalInt.empty(); + } + + @Override + public void updateOptions(ClientInformation clientOptions) { + } + + @Override + public void displayClientMessage(Component message, boolean actionBar) { + } + + @Override + public void awardStat(Stat stat, int amount) { + } + + @Override + public void awardStat(Stat stat) { + } + + @Override + public boolean isInvulnerableTo(DamageSource damageSource) { + return true; + } + + @Override + public void openTextEdit(SignBlockEntity sign, boolean front) { + } +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightWorldNativeAccess.java new file mode 100644 index 000000000..ac5baa35f --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightWorldNativeAccess.java @@ -0,0 +1,181 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2; + +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import com.sk89q.worldedit.world.block.BlockState; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.FullChunkStatus; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.chunk.LevelChunk; +import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData; +import org.bukkit.event.block.BlockPhysicsEvent; + +import java.lang.ref.WeakReference; +import java.util.Objects; +import javax.annotation.Nullable; + +public class PaperweightWorldNativeAccess implements WorldNativeAccess { + private static final int UPDATE = 1; + private static final int NOTIFY = 2; + + private final com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2.PaperweightAdapter adapter; + private final WeakReference world; + private SideEffectSet sideEffectSet; + + public PaperweightWorldNativeAccess(com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2.PaperweightAdapter adapter, WeakReference world) { + this.adapter = adapter; + this.world = world; + } + + private ServerLevel getWorld() { + return Objects.requireNonNull(world.get(), "The reference to the world was lost"); + } + + @Override + public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + @Override + public LevelChunk getChunk(int x, int z) { + return getWorld().getChunk(x, z); + } + + @Override + public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) { + int stateId = BlockStateIdAccess.getBlockStateId(state); + return BlockStateIdAccess.isValidInternalId(stateId) + ? Block.stateById(stateId) + : ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); + } + + @Override + public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk chunk, BlockPos position) { + return chunk.getBlockState(position); + } + + @Nullable + @Override + public net.minecraft.world.level.block.state.BlockState setBlockState(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState state) { + return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE)); + } + + @Override + public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(net.minecraft.world.level.block.state.BlockState block, BlockPos position) { + return Block.updateFromNeighbourShapes(block, getWorld(), position); + } + + @Override + public BlockPos getPosition(int x, int y, int z) { + return new BlockPos(x, y, z); + } + + @Override + public void updateLightingForBlock(BlockPos position) { + getWorld().getChunkSource().getLightEngine().checkBlock(position); + } + + @Override + public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { + return false; + } + + @Override + public void notifyBlockUpdate(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { + if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { + getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY); + } + } + + @Override + public boolean isChunkTicking(LevelChunk chunk) { + return chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING); + } + + @Override + public void markBlockChanged(LevelChunk chunk, BlockPos position) { + if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { + getWorld().getChunkSource().blockChanged(position); + } + } + + @Override + public void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { + ServerLevel world = getWorld(); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + world.updateNeighborsAt(pos, oldState.getBlock()); + } else { + // When we don't want events, manually run the physics without them. + Block block = oldState.getBlock(); + fireNeighborChanged(pos, world, block, pos.west()); + fireNeighborChanged(pos, world, block, pos.east()); + fireNeighborChanged(pos, world, block, pos.below()); + fireNeighborChanged(pos, world, block, pos.above()); + fireNeighborChanged(pos, world, block, pos.north()); + fireNeighborChanged(pos, world, block, pos.south()); + } + if (newState.hasAnalogOutputSignal()) { + world.updateNeighbourForOutputSignal(pos, newState.getBlock()); + } + } + + // Not sure why neighborChanged is deprecated + @SuppressWarnings("deprecation") + private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { + world.getBlockState(neighborPos).neighborChanged(world, neighborPos, block, pos, false); + } + + @Override + public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) { + ServerLevel world = getWorld(); + // a == updateNeighbors + // b == updateDiagonalNeighbors + oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + CraftWorld craftWorld = world.getWorld(); + BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState)); + world.getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + } + newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit); + newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); + } + + @Override + public void onBlockStateChange(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { + getWorld().onBlockStateChange(pos, oldState, newState); + } + + @Override + public void flush() { + + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightBlockMaterial.java new file mode 100644 index 000000000..2e1dd8279 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightBlockMaterial.java @@ -0,0 +1,185 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; + +import com.google.common.base.Suppliers; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.util.ReflectionUtil; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.EmptyBlockGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.LiquidBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.PushReaction; +import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData; + +public class PaperweightBlockMaterial implements BlockMaterial { + + private final Block block; + private final BlockState blockState; + private final boolean isTranslucent; + private final CraftBlockData craftBlockData; + private final org.bukkit.Material craftMaterial; + private final int opacity; + private final CompoundTag tile; + + public PaperweightBlockMaterial(Block block) { + this(block, block.defaultBlockState()); + } + + public PaperweightBlockMaterial(Block block, BlockState blockState) { + this.block = block; + this.blockState = blockState; + this.craftBlockData = CraftBlockData.fromData(blockState); + this.craftMaterial = craftBlockData.getMaterial(); + BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, + Refraction.pickName("properties", "aN")); + this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo, + Refraction.pickName("canOcclude", "m") + ); + opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); + BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity( + BlockPos.ZERO, + blockState + ); + tile = tileEntity == null + ? null + : new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); + } + + public Block getBlock() { + return block; + } + + public BlockState getState() { + return blockState; + } + + public CraftBlockData getCraftBlockData() { + return craftBlockData; + } + + @Override + public boolean isAir() { + return blockState.isAir(); + } + + @Override + public boolean isFullCube() { + return craftMaterial.isOccluding(); + } + + @Override + public boolean isOpaque() { + return blockState.isOpaque(); + } + + @Override + public boolean isPowerSource() { + return blockState.isSignalSource(); + } + + @Override + public boolean isLiquid() { + // TODO: Better check ? + return block instanceof LiquidBlock; + } + + @Override + public boolean isSolid() { + // TODO: Replace + return blockState.isSolid(); + } + + @Override + public float getHardness() { + return craftBlockData.getState().destroySpeed; + } + + @Override + public float getResistance() { + return block.getExplosionResistance(); + } + + @Override + public float getSlipperiness() { + return block.getFriction(); + } + + @Override + public int getLightValue() { + return blockState.getLightEmission(); + } + + @Override + public int getLightOpacity() { + return opacity; + } + + @Override + public boolean isFragileWhenPushed() { + return blockState.getPistonPushReaction() == PushReaction.DESTROY; + } + + @Override + public boolean isUnpushable() { + return blockState.getPistonPushReaction() == PushReaction.BLOCK; + } + + @Override + public boolean isTicksRandomly() { + return block.isRandomlyTicking(blockState); + } + + @Override + public boolean isMovementBlocker() { + return craftMaterial.isSolid(); + } + + @Override + public boolean isBurnable() { + return craftMaterial.isBurnable(); + } + + @Override + public boolean isToolRequired() { + // Removed in 1.16.1, this is not present in higher versions + return false; + } + + @Override + public boolean isReplacedDuringPlacement() { + return blockState.canBeReplaced(); + } + + @Override + public boolean isTranslucent() { + return isTranslucent; + } + + @Override + public boolean hasContainer() { + return block instanceof EntityBlock; + } + + @Override + public boolean isTile() { + return block instanceof EntityBlock; + } + + @Override + public CompoundTag getDefaultTile() { + return tile; + } + + @Override + public int getMapColor() { + // rgb field + return block.defaultMapColor().col; + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java new file mode 100644 index 000000000..a9e657b2e --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java @@ -0,0 +1,652 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; + +import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; +import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter; +import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; +import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.entity.LazyBaseEntity; +import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; +import com.fastasyncworldedit.core.queue.IBatchProcessor; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; +import com.fastasyncworldedit.core.util.NbtUtils; +import com.fastasyncworldedit.core.util.TaskManager; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2.PaperweightAdapter; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.regen.PaperweightRegen; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +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.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.nbt.BinaryTag; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import com.sk89q.worldedit.util.nbt.StringBinaryTag; +import com.sk89q.worldedit.world.RegenOptions; +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.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import io.papermc.lib.PaperLib; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Registry; +import net.minecraft.core.WritableRegistry; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.StringRepresentable; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.chunk.LevelChunk; +import org.apache.logging.log4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.TreeType; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_20_R2.CraftServer; +import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_20_R2.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_20_R2.util.CraftNamespacedKey; +import org.bukkit.entity.Player; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.OptionalInt; +import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static net.minecraft.core.registries.Registries.BIOME; + +public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements + IDelegateBukkitImplAdapter { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; + + static { + try { + CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE = ChunkHolder.class.getDeclaredMethod("wasAccessibleSinceLastSave"); + } catch (NoSuchMethodException ignored) { // may not be present in newer paper versions + } + } + + private final PaperweightAdapter parent; + // ------------------------------------------------------------------------ + // Code that may break between versions of Minecraft + // ------------------------------------------------------------------------ + private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil(); + private char[] ibdToStateOrdinal = null; + private int[] ordinalToIbdID = null; + private boolean initialised = false; + private Map>> allBlockProperties = null; + + public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { + this.parent = new PaperweightAdapter(); + } + + @Nullable + private static String getEntityId(Entity entity) { + ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType()); + return resourceLocation == null ? null : resourceLocation.toString(); + } + + private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { + entity.save(compoundTag); + } + + @Override + public BukkitImplAdapter getParent() { + return parent; + } + + private synchronized boolean init() { + if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) { + return false; + } + ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size + ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size + for (int i = 0; i < ibdToStateOrdinal.length; i++) { + BlockState blockState = BlockTypesCache.states[i]; + PaperweightBlockMaterial material = (PaperweightBlockMaterial) blockState.getMaterial(); + int id = Block.BLOCK_STATE_REGISTRY.getId(material.getState()); + char ordinal = blockState.getOrdinalChar(); + ibdToStateOrdinal[id] = ordinal; + ordinalToIbdID[ordinal] = id; + } + Map>> properties = new HashMap<>(); + try { + for (Field field : BlockStateProperties.class.getDeclaredFields()) { + Object obj = field.get(null); + if (!(obj instanceof net.minecraft.world.level.block.state.properties.Property state)) { + continue; + } + Property property; + if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + property = new BooleanProperty( + state.getName(), + (List) ImmutableList.copyOf(state.getPossibleValues()) + ); + } else if (state instanceof DirectionProperty) { + property = new DirectionalProperty( + state.getName(), + state + .getPossibleValues() + .stream() + .map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase())) + .collect(Collectors.toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + property = new EnumProperty( + state.getName(), + state + .getPossibleValues() + .stream() + .map(e -> ((StringRepresentable) e).getSerializedName()) + .collect(Collectors.toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + property = new IntegerProperty( + state.getName(), + (List) ImmutableList.copyOf(state.getPossibleValues()) + ); + } else { + throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state + .getClass() + .getSimpleName()); + } + properties.compute(property.getName().toLowerCase(Locale.ROOT), (k, v) -> { + if (v == null) { + v = new ArrayList<>(Collections.singletonList(property)); + } else { + v.add(property); + } + return v; + }); + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } finally { + allBlockProperties = ImmutableMap.copyOf(properties); + } + initialised = true; + return true; + } + + @Override + public BlockMaterial getMaterial(BlockType blockType) { + Block block = getBlock(blockType); + return new PaperweightBlockMaterial(block); + } + + @Override + public synchronized BlockMaterial getMaterial(BlockState state) { + net.minecraft.world.level.block.state.BlockState blockState = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState(); + return new PaperweightBlockMaterial(blockState.getBlock(), blockState); + } + + public Block getBlock(BlockType blockType) { + return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK) + .get(new ResourceLocation(blockType.getNamespace(), blockType.getResource())); + } + + @Deprecated + @Override + public BlockState getBlock(Location location) { + Preconditions.checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); + BlockState state = adapt(blockData); + if (state == null) { + org.bukkit.block.Block bukkitBlock = location.getBlock(); + state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } + return state; + } + + @Override + public BaseBlock getFullBlock(final Location location) { + Preconditions.checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); + BlockState state = adapt(blockData); + if (state == null) { + org.bukkit.block.Block bukkitBlock = location.getBlock(); + state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } + if (state.getBlockType().getMaterial().hasContainer()) { + + // Read the NBT data + BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); + if (blockEntity != null) { + net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); + return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); + } + } + + return state.toBaseBlock(); + } + + @Override + public Set getSupportedSideEffects() { + return SideEffectSet.defaults().getSideEffectsToApply(); + } + + @Override + public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + return new PaperweightFaweWorldNativeAccess( + this, + new WeakReference<>(((CraftWorld) world).getHandle()) + ); + } + + @Override + public BaseEntity getEntity(org.bukkit.entity.Entity entity) { + Preconditions.checkNotNull(entity); + + CraftEntity craftEntity = ((CraftEntity) entity); + Entity mcEntity = craftEntity.getHandle(); + + String id = getEntityId(mcEntity); + + if (id != null) { + EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); + Supplier saveTag = () -> { + final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); + readEntityIntoTag(mcEntity, minecraftTag); + //add Id for AbstractChangeSet to work + final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); + final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); + tags.put("Id", StringBinaryTag.of(id)); + return CompoundBinaryTag.from(tags); + }; + return new LazyBaseEntity(type, saveTag); + } else { + return null; + } + } + + @Override + public Component getRichBlockName(BlockType blockType) { + return parent.getRichBlockName(blockType); + } + + @Override + public Component getRichItemName(ItemType itemType) { + return parent.getRichItemName(itemType); + } + + @Override + public Component getRichItemName(BaseItemStack itemStack) { + return parent.getRichItemName(itemStack); + } + + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); + net.minecraft.world.level.block.state.BlockState mcState = material.getCraftBlockData().getState(); + return OptionalInt.of(Block.BLOCK_STATE_REGISTRY.getId(mcState)); + } + + @Override + public BlockState adapt(BlockData blockData) { + CraftBlockData cbd = ((CraftBlockData) blockData); + net.minecraft.world.level.block.state.BlockState ibd = cbd.getState(); + return adapt(ibd); + } + + public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) { + return BlockTypesCache.states[adaptToChar(blockState)]; + } + + public char adaptToChar(net.minecraft.world.level.block.state.BlockState blockState) { + int id = Block.BLOCK_STATE_REGISTRY.getId(blockState); + if (initialised) { + return ibdToStateOrdinal[id]; + } + synchronized (this) { + if (initialised) { + return ibdToStateOrdinal[id]; + } + try { + init(); + return ibdToStateOrdinal[id]; + } catch (ArrayIndexOutOfBoundsException e1) { + LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!", + blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1 + ); + return BlockTypesCache.ReservedIDs.AIR; + } + } + } + + public char ibdIDToOrdinal(int id) { + if (initialised) { + return ibdToStateOrdinal[id]; + } + synchronized (this) { + if (initialised) { + return ibdToStateOrdinal[id]; + } + init(); + return ibdToStateOrdinal[id]; + } + } + + @Override + public char[] getIbdToStateOrdinal() { + if (initialised) { + return ibdToStateOrdinal; + } + synchronized (this) { + if (initialised) { + return ibdToStateOrdinal; + } + init(); + return ibdToStateOrdinal; + } + } + + public int ordinalToIbdID(char ordinal) { + if (initialised) { + return ordinalToIbdID[ordinal]; + } + synchronized (this) { + if (initialised) { + return ordinalToIbdID[ordinal]; + } + init(); + return ordinalToIbdID[ordinal]; + } + } + + @Override + public int[] getOrdinalToIbdID() { + if (initialised) { + return ordinalToIbdID; + } + synchronized (this) { + if (initialised) { + return ordinalToIbdID; + } + init(); + return ordinalToIbdID; + } + } + + @Override + public > BlockData adapt(B state) { + PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); + return material.getCraftBlockData(); + } + + @Override + public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { + ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); + if (map != null && wasAccessibleSinceLastSave(map)) { + boolean flag = false; + // PlayerChunk.d players = map.players; + Stream stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag) + */ Stream.empty(); + + ServerPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle(); + stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer) + .forEach(entityPlayer -> { + synchronized (chunkPacket) { + ClientboundLevelChunkWithLightPacket nmsPacket = (ClientboundLevelChunkWithLightPacket) chunkPacket.getNativePacket(); + if (nmsPacket == null) { + nmsPacket = mapUtil.create(this, chunkPacket); + chunkPacket.setNativePacket(nmsPacket); + } + try { + FaweCache.INSTANCE.CHUNK_FLAG.get().set(true); + entityPlayer.connection.send(nmsPacket); + } finally { + FaweCache.INSTANCE.CHUNK_FLAG.get().set(false); + } + } + }); + } + } + + @Override + public Map> getProperties(BlockType blockType) { + return getParent().getProperties(blockType); + } + + @Override + public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) { + int internalId = BlockStateIdAccess.getBlockStateId(blockState); + net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); + return blockState1.hasPostProcess( + ((CraftWorld) world).getHandle(), + new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) + ); + } + + @Override + public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { + ItemStack stack = new ItemStack( + DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM) + .get(ResourceLocation.tryParse(baseItemStack.getType().getId())), + baseItemStack.getAmount() + ); + stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()))); + return CraftItemStack.asCraftMirror(stack); + } + + @Override + public boolean generateTree( + TreeGenerator.TreeType treeType, EditSession editSession, BlockVector3 blockVector3, + org.bukkit.World bukkitWorld + ) { + TreeType bukkitType = BukkitWorld.toBukkitTreeType(treeType); + if (bukkitType == TreeType.CHORUS_PLANT) { + blockVector3 = blockVector3.add( + 0, + 1, + 0 + ); // bukkit skips the feature gen which does this offset normally, so we have to add it back + } + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + final BlockVector3 finalBlockVector = blockVector3; + // Sync to main thread to ensure no clashes occur + Map placed = TaskManager.taskManager().sync(() -> { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + try { + if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) { + return null; + } + return ImmutableMap.copyOf(serverLevel.capturedBlockStates); + } finally { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + }); + if (placed == null || placed.isEmpty()) { + return false; + } + for (CraftBlockState craftBlockState : placed.values()) { + if (craftBlockState == null || craftBlockState.getType() == Material.AIR) { + continue; + } + editSession.setBlock(craftBlockState.getX(), craftBlockState.getY(), craftBlockState.getZ(), + BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData()) + ); + } + return true; + } + + @Override + public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { + final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); + final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); + weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); + return weStack; + } + + @Override + public Tag toNative(net.minecraft.nbt.Tag foreign) { + return parent.toNative(foreign); + } + + @Override + public net.minecraft.nbt.Tag fromNative(Tag foreign) { + if (foreign instanceof PaperweightLazyCompoundTag) { + return ((PaperweightLazyCompoundTag) foreign).get(); + } + return parent.fromNative(foreign); + } + + @Override + public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { + return new PaperweightRegen(bukkitWorld, region, target, options).regenerate(); + } + + @Override + public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { + return new PaperweightGetBlocks(world, chunkX, chunkZ); + } + + @Override + public int getInternalBiomeId(BiomeType biomeType) { + final Registry registry = MinecraftServer + .getServer() + .registryAccess() + .registryOrThrow(BIOME); + ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.getId()); + Biome biome = registry.get(resourceLocation); + return registry.getId(biome); + } + + @Override + public Iterable getRegisteredBiomes() { + WritableRegistry biomeRegistry = (WritableRegistry) ((CraftServer) Bukkit.getServer()) + .getServer() + .registryAccess() + .registryOrThrow(BIOME); + List keys = biomeRegistry.stream() + .map(biomeRegistry::getKey).filter(Objects::nonNull).toList(); + List namespacedKeys = new ArrayList<>(); + for (ResourceLocation key : keys) { + try { + namespacedKeys.add(CraftNamespacedKey.fromMinecraft(key)); + } catch (IllegalArgumentException e) { + LOGGER.error("Error converting biome key {}", key.toString(), e); + } + } + return namespacedKeys; + } + + @Override + public RelighterFactory getRelighterFactory() { + if (PaperLib.isPaper()) { + return new PaperweightStarlightRelighterFactory(); + } else { + return new NMSRelighterFactory(); + } + } + + @Override + public Map>> getAllProperties() { + if (initialised) { + return allBlockProperties; + } + synchronized (this) { + if (initialised) { + return allBlockProperties; + } + init(); + return allBlockProperties; + } + } + + @Override + public IBatchProcessor getTickingPostProcessor() { + return new PaperweightPostProcessor(); + } + + private boolean wasAccessibleSinceLastSave(ChunkHolder holder) { + if (!PaperLib.isPaper() || !PaperweightPlatformAdapter.POST_CHUNK_REWRITE) { + try { + return (boolean) CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE.invoke(holder); + } catch (IllegalAccessException | InvocationTargetException ignored) { + // fall-through + } + } + // Papers new chunk system has no related replacement - therefor we assume true. + return true; + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweWorldNativeAccess.java new file mode 100644 index 000000000..b452ec4cd --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweWorldNativeAccess.java @@ -0,0 +1,287 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; + +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.math.IntPair; +import com.fastasyncworldedit.core.util.TaskManager; +import com.fastasyncworldedit.core.util.task.RunnableVal; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import com.sk89q.worldedit.world.block.BlockState; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.FullChunkStatus; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData; +import org.bukkit.event.block.BlockPhysicsEvent; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess { + + private static final int UPDATE = 1; + private static final int NOTIFY = 2; + private static final Direction[] NEIGHBOUR_ORDER = { + Direction.EAST, + Direction.WEST, + Direction.DOWN, + Direction.UP, + Direction.NORTH, + Direction.SOUTH + }; + private final PaperweightFaweAdapter paperweightFaweAdapter; + private final WeakReference level; + private final AtomicInteger lastTick; + private final Set cachedChanges = new HashSet<>(); + private final Set cachedChunksToSend = new HashSet<>(); + private SideEffectSet sideEffectSet; + + public PaperweightFaweWorldNativeAccess(PaperweightFaweAdapter paperweightFaweAdapter, WeakReference level) { + this.paperweightFaweAdapter = paperweightFaweAdapter; + this.level = level; + // Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging. + // - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway. + this.lastTick = new AtomicInteger(MinecraftServer.currentTick); + } + + private Level getLevel() { + return Objects.requireNonNull(level.get(), "The reference to the world was lost"); + } + + @Override + public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + @Override + public LevelChunk getChunk(int x, int z) { + return getLevel().getChunk(x, z); + } + + @Override + public net.minecraft.world.level.block.state.BlockState toNative(BlockState blockState) { + int stateId = paperweightFaweAdapter.ordinalToIbdID(blockState.getOrdinalChar()); + return BlockStateIdAccess.isValidInternalId(stateId) + ? Block.stateById(stateId) + : ((CraftBlockData) BukkitAdapter.adapt(blockState)).getState(); + } + + @Override + public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk levelChunk, BlockPos blockPos) { + return levelChunk.getBlockState(blockPos); + } + + @Nullable + @Override + public synchronized net.minecraft.world.level.block.state.BlockState setBlockState( + LevelChunk levelChunk, BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState blockState + ) { + int currentTick = MinecraftServer.currentTick; + if (Fawe.isMainThread()) { + return levelChunk.setBlockState(blockPos, blockState, + this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE) + ); + } + // Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( ) + cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState)); + cachedChunksToSend.add(new IntPair(levelChunk.locX, levelChunk.locZ)); + boolean nextTick = lastTick.get() > currentTick; + if (nextTick || cachedChanges.size() >= 1024) { + if (nextTick) { + lastTick.set(currentTick); + } + flushAsync(nextTick); + } + return blockState; + } + + @Override + public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition( + net.minecraft.world.level.block.state.BlockState blockState, + BlockPos blockPos + ) { + return Block.updateFromNeighbourShapes(blockState, getLevel(), blockPos); + } + + @Override + public BlockPos getPosition(int x, int y, int z) { + return new BlockPos(x, y, z); + } + + @Override + public void updateLightingForBlock(BlockPos blockPos) { + getLevel().getChunkSource().getLightEngine().checkBlock(blockPos); + } + + @Override + public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) { + // We will assume that the tile entity was created for us, + // though we do not do this on the other versions + BlockEntity blockEntity = getLevel().getBlockEntity(blockPos); + if (blockEntity == null) { + return false; + } + net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeBinary(tag); + blockEntity.load((CompoundTag) nativeTag); + return true; + } + + @Override + public void notifyBlockUpdate( + LevelChunk levelChunk, BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { + getLevel().sendBlockUpdated(blockPos, oldState, newState, UPDATE | NOTIFY); + } + } + + @Override + public boolean isChunkTicking(LevelChunk levelChunk) { + return levelChunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING); + } + + @Override + public void markBlockChanged(LevelChunk levelChunk, BlockPos blockPos) { + if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { + ((ServerChunkCache) getLevel().getChunkSource()).blockChanged(blockPos); + } + } + + @Override + public void notifyNeighbors( + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + Level level = getLevel(); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + level.blockUpdated(blockPos, oldState.getBlock()); + } else { + // When we don't want events, manually run the physics without them. + // Un-nest neighbour updating + for (Direction direction : NEIGHBOUR_ORDER) { + BlockPos shifted = blockPos.relative(direction); + level.getBlockState(shifted).neighborChanged(level, shifted, oldState.getBlock(), blockPos, false); + } + } + if (newState.hasAnalogOutputSignal()) { + level.updateNeighbourForOutputSignal(blockPos, newState.getBlock()); + } + } + + @Override + public void updateNeighbors( + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState, + int recursionLimit + ) { + Level level = getLevel(); + // a == updateNeighbors + // b == updateDiagonalNeighbors + oldState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + CraftWorld craftWorld = level.getWorld(); + if (craftWorld != null) { + BlockPhysicsEvent event = new BlockPhysicsEvent( + craftWorld.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()), + CraftBlockData.fromData(newState) + ); + level.getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + } + } + newState.triggerEvent(level, blockPos, NOTIFY, recursionLimit); + newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); + } + + @Override + public void onBlockStateChange( + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + getLevel().onBlockStateChange(blockPos, oldState, newState); + } + + private synchronized void flushAsync(final boolean sendChunks) { + final Set changes = Set.copyOf(cachedChanges); + cachedChanges.clear(); + final Set toSend; + if (sendChunks) { + toSend = Set.copyOf(cachedChunksToSend); + cachedChunksToSend.clear(); + } else { + toSend = Collections.emptySet(); + } + RunnableVal runnableVal = new RunnableVal<>() { + @Override + public void run(Object value) { + changes.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, + sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) + )); + if (!sendChunks) { + return; + } + for (IntPair chunk : toSend) { + PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); + } + } + }; + TaskManager.taskManager().async(() -> TaskManager.taskManager().sync(runnableVal)); + } + + @Override + public synchronized void flush() { + RunnableVal runnableVal = new RunnableVal<>() { + @Override + public void run(Object value) { + cachedChanges.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, + sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) + )); + for (IntPair chunk : cachedChunksToSend) { + PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); + } + } + }; + if (Fawe.isMainThread()) { + runnableVal.run(); + } else { + TaskManager.taskManager().sync(runnableVal); + } + cachedChanges.clear(); + cachedChunksToSend.clear(); + } + + private record CachedChange( + LevelChunk levelChunk, + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState blockState + ) { + + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java new file mode 100644 index 000000000..d21510ff6 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java @@ -0,0 +1,1147 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; + +import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; +import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import com.fastasyncworldedit.core.queue.implementation.QueueHandler; +import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; +import com.fastasyncworldedit.core.util.MathMan; +import com.fastasyncworldedit.core.util.collection.AdaptedMap; +import com.google.common.base.Suppliers; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import io.papermc.lib.PaperLib; +import io.papermc.paper.event.block.BeaconDeactivatedEvent; +import net.minecraft.core.*; +import net.minecraft.nbt.IntTag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.util.BitStorage; +import net.minecraft.util.ZeroBitStorage; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.entity.BeaconBlockEntity; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.*; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.apache.logging.log4j.Logger; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlock; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import javax.annotation.Nonnull; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.Semaphore; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static net.minecraft.core.registries.Registries.BIOME; + +public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private static final Function posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); + private static final Function nmsTile2We = + tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); + private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin + .getInstance() + .getBukkitImplAdapter()); + private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); + private final ServerLevel serverLevel; + private final int chunkX; + private final int chunkZ; + private final int minHeight; + private final int maxHeight; + private final int minSectionPosition; + private final int maxSectionPosition; + private final Registry biomeRegistry; + private final IdMap> biomeHolderIdMap; + private LevelChunkSection[] sections; + private LevelChunk levelChunk; + private DataLayer[] blockLight; + private DataLayer[] skyLight; + private boolean createCopy = false; + private PaperweightGetBlocks_Copy copy = null; + private boolean forceLoadSections = true; + private boolean lightUpdate = false; + + public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { + this(((CraftWorld) world).getHandle(), chunkX, chunkZ); + } + + public PaperweightGetBlocks(ServerLevel serverLevel, int chunkX, int chunkZ) { + super(serverLevel.getMinBuildHeight() >> 4, (serverLevel.getMaxBuildHeight() - 1) >> 4); + this.serverLevel = serverLevel; + this.chunkX = chunkX; + this.chunkZ = chunkZ; + this.minHeight = serverLevel.getMinBuildHeight(); + this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. + this.minSectionPosition = minHeight >> 4; + this.maxSectionPosition = maxHeight >> 4; + this.skyLight = new DataLayer[getSectionCount()]; + this.blockLight = new DataLayer[getSectionCount()]; + this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME); + this.biomeHolderIdMap = biomeRegistry.asHolderIdMap(); + } + + public int getChunkX() { + return chunkX; + } + + public int getChunkZ() { + return chunkZ; + } + + @Override + public boolean isCreateCopy() { + return createCopy; + } + + @Override + public void setCreateCopy(boolean createCopy) { + this.createCopy = createCopy; + } + + @Override + public IChunkGet getCopy() { + return copy; + } + + @Override + public void setLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { + if (light != null) { + lightUpdate = true; + try { + fillLightNibble(light, LightLayer.BLOCK, minSectionPosition, maxSectionPosition); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + @Override + public void setSkyLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { + if (light != null) { + lightUpdate = true; + try { + fillLightNibble(light, LightLayer.SKY, minSectionPosition, maxSectionPosition); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + @Override + public void setHeightmapToGet(HeightMapType type, int[] data) { + // height + 1 to match server internal + BitArrayUnstretched bitArray = new BitArrayUnstretched(MathMan.log2nlz(getChunk().getHeight() + 1), 256); + bitArray.fromRaw(data); + Heightmap.Types nativeType = Heightmap.Types.valueOf(type.name()); + Heightmap heightMap = getChunk().heightmaps.get(nativeType); + heightMap.setRawData(getChunk(), nativeType, bitArray.getData()); + } + + @Override + public int getMaxY() { + return maxHeight; + } + + @Override + public int getMinY() { + return minHeight; + } + + @Override + public BiomeType getBiomeType(int x, int y, int z) { + LevelChunkSection section = getSections(false)[(y >> 4) - getMinSectionPosition()]; + Holder biomes = section.getNoiseBiome(x >> 2, (y & 15) >> 2, z >> 2); + return PaperweightPlatformAdapter.adapt(biomes, serverLevel); + } + + @Override + public void removeSectionLighting(int layer, boolean sky) { + SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.BLOCK).getDataLayerData( + sectionPos); + if (dataLayer != null) { + lightUpdate = true; + synchronized (dataLayer) { + byte[] bytes = dataLayer.getData(); + Arrays.fill(bytes, (byte) 0); + } + } + if (sky) { + SectionPos sectionPos1 = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer1 = serverLevel + .getChunkSource() + .getLightEngine() + .getLayerListener(LightLayer.SKY) + .getDataLayerData(sectionPos1); + if (dataLayer1 != null) { + lightUpdate = true; + synchronized (dataLayer1) { + byte[] bytes = dataLayer1.getData(); + Arrays.fill(bytes, (byte) 0); + } + } + } + } + + @Override + public CompoundTag getTile(int x, int y, int z) { + BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( + chunkX << 4), y, (z & 15) + ( + chunkZ << 4))); + if (blockEntity == null) { + return null; + } + return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)); + } + + @Override + public Map getTiles() { + Map nmsTiles = getChunk().getBlockEntities(); + if (nmsTiles.isEmpty()) { + return Collections.emptyMap(); + } + return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); + } + + @Override + public int getSkyLight(int x, int y, int z) { + int layer = y >> 4; + int alayer = layer - getMinSectionPosition(); + if (skyLight[alayer] == null) { + SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer = + serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.SKY).getDataLayerData(sectionPos); + // If the server hasn't generated the section's NibbleArray yet, it will be null + if (dataLayer == null) { + byte[] LAYER_COUNT = new byte[2048]; + // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. + Arrays.fill(LAYER_COUNT, (byte) 15); + dataLayer = new DataLayer(LAYER_COUNT); + ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( + LightLayer.BLOCK, + sectionPos, + dataLayer + ); + } + skyLight[alayer] = dataLayer; + } + return skyLight[alayer].get(x & 15, y & 15, z & 15); + } + + @Override + public int getEmittedLight(int x, int y, int z) { + int layer = y >> 4; + int alayer = layer - getMinSectionPosition(); + if (blockLight[alayer] == null) { + serverLevel.getRawBrightness(new BlockPos(1, 1, 1), 5); + SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer = serverLevel + .getChunkSource() + .getLightEngine() + .getLayerListener(LightLayer.BLOCK) + .getDataLayerData(sectionPos); + // If the server hasn't generated the section's DataLayer yet, it will be null + if (dataLayer == null) { + byte[] LAYER_COUNT = new byte[2048]; + // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. + Arrays.fill(LAYER_COUNT, (byte) 15); + dataLayer = new DataLayer(LAYER_COUNT); + ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos, + dataLayer + ); + } + blockLight[alayer] = dataLayer; + } + return blockLight[alayer].get(x & 15, y & 15, z & 15); + } + + @Override + public int[] getHeightMap(HeightMapType type) { + long[] longArray = getChunk().heightmaps.get(Heightmap.Types.valueOf(type.name())).getRawData(); + BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256, longArray); + return bitArray.toRaw(new int[256]); + } + + @Override + public CompoundTag getEntity(UUID uuid) { + Entity entity = serverLevel.getEntity(uuid); + if (entity != null) { + org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); + return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); + } + for (CompoundTag tag : getEntities()) { + if (uuid.equals(tag.getUUID())) { + return tag; + } + } + return null; + } + + @Override + public Set getEntities() { + ensureLoaded(serverLevel, chunkX, chunkZ); + List entities = PaperweightPlatformAdapter.getEntities(getChunk()); + if (entities.isEmpty()) { + return Collections.emptySet(); + } + int size = entities.size(); + return new AbstractSet<>() { + @Override + public int size() { + return size; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean contains(Object get) { + if (!(get instanceof CompoundTag getTag)) { + return false; + } + UUID getUUID = getTag.getUUID(); + for (Entity entity : entities) { + UUID uuid = entity.getUUID(); + if (uuid.equals(getUUID)) { + return true; + } + } + return false; + } + + @Nonnull + @Override + public Iterator iterator() { + Iterable result = entities.stream().map(input -> { + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + input.save(tag); + return (CompoundTag) adapter.toNative(tag); + }).collect(Collectors.toList()); + return result.iterator(); + } + }; + } + + private void removeEntity(Entity entity) { + entity.discard(); + } + + public LevelChunk ensureLoaded(ServerLevel nmsWorld, int chunkX, int chunkZ) { + return PaperweightPlatformAdapter.ensureLoaded(nmsWorld, chunkX, chunkZ); + } + + @Override + @SuppressWarnings("rawtypes") + public synchronized > T call(IChunkSet set, Runnable finalizer) { + forceLoadSections = false; + copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + try { + ServerLevel nmsWorld = serverLevel; + LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); + + // Remove existing tiles. Create a copy so that we can remove blocks + Map chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); + List beacons = null; + if (!chunkTiles.isEmpty()) { + for (Map.Entry entry : chunkTiles.entrySet()) { + final BlockPos pos = entry.getKey(); + final int lx = pos.getX() & 15; + final int ly = pos.getY(); + final int lz = pos.getZ() & 15; + final int layer = ly >> 4; + if (!set.hasSection(layer)) { + continue; + } + + int ordinal = set.getBlock(lx, ly, lz).getOrdinal(); + if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) { + BlockEntity tile = entry.getValue(); + if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) { + if (beacons == null) { + beacons = new ArrayList<>(); + } + beacons.add(tile); + PaperweightPlatformAdapter.removeBeacon(tile, nmsChunk); + continue; + } + nmsChunk.removeBlockEntity(tile.getBlockPos()); + if (createCopy) { + copy.storeTile(tile); + } + } + } + } + final BiomeType[][] biomes = set.getBiomes(); + + int bitMask = 0; + synchronized (nmsChunk) { + LevelChunkSection[] levelChunkSections = nmsChunk.getSections(); + + for (int layerNo = getMinSectionPosition(); layerNo <= getMaxSectionPosition(); layerNo++) { + + int getSectionIndex = layerNo - getMinSectionPosition(); + int setSectionIndex = layerNo - set.getMinSectionPosition(); + + if (!set.hasSection(layerNo)) { + // No blocks, but might be biomes present. Handle this lazily. + if (biomes == null) { + continue; + } + if (layerNo < set.getMinSectionPosition() || layerNo > set.getMaxSectionPosition()) { + continue; + } + if (biomes[setSectionIndex] != null) { + synchronized (super.sectionLocks[getSectionIndex]) { + LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; + if (createCopy && existingSection != null) { + copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); + } + + if (existingSection == null) { + PalettedContainer> biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer( + biomes[setSectionIndex], + biomeHolderIdMap + ); + LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + new char[4096], + adapter, + biomeRegistry, + biomeData + ); + if (PaperweightPlatformAdapter.setSectionAtomic( + levelChunkSections, + null, + newSection, + getSectionIndex + )) { + updateGet(nmsChunk, levelChunkSections, newSection, new char[4096], getSectionIndex); + continue; + } else { + existingSection = levelChunkSections[getSectionIndex]; + if (existingSection == null) { + LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, + getSectionIndex + ); + continue; + } + } + } else { + setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); + } + } + } + continue; + } + + bitMask |= 1 << getSectionIndex; + + // setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to + // this chunk GET when #updateGet is called. Future dords, please listen this time. + char[] tmp = set.load(layerNo); + char[] setArr = new char[tmp.length]; + System.arraycopy(tmp, 0, setArr, 0, tmp.length); + + // synchronise on internal section to avoid circular locking with a continuing edit if the chunk was + // submitted to keep loaded internal chunks to queue target size. + synchronized (super.sectionLocks[getSectionIndex]) { + + LevelChunkSection newSection; + LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; + // Don't attempt to tick section whilst we're editing + if (existingSection != null) { + PaperweightPlatformAdapter.clearCounts(existingSection); + if (PaperLib.isPaper()) { + existingSection.tickingList.clear(); + } + } + + if (createCopy) { + char[] tmpLoad = loadPrivately(layerNo); + char[] copyArr = new char[4096]; + System.arraycopy(tmpLoad, 0, copyArr, 0, 4096); + copy.storeSection(getSectionIndex, copyArr); + if (biomes != null && existingSection != null) { + copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); + } + } + + if (existingSection == null) { + PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( + biomeHolderIdMap, + biomeHolderIdMap.byIdOrThrow(WorldEditPlugin + .getInstance() + .getBukkitImplAdapter() + .getInternalBiomeId( + BiomeTypes.PLAINS)), + PalettedContainer.Strategy.SECTION_BIOMES + ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + setArr, + adapter, + biomeRegistry, + biomeData + ); + if (PaperweightPlatformAdapter.setSectionAtomic( + levelChunkSections, + null, + newSection, + getSectionIndex + )) { + updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); + continue; + } else { + existingSection = levelChunkSections[getSectionIndex]; + if (existingSection == null) { + LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, + getSectionIndex + ); + continue; + } + } + } + + //ensure that the server doesn't try to tick the chunksection while we're editing it. (Again) + PaperweightPlatformAdapter.clearCounts(existingSection); + if (PaperLib.isPaper()) { + existingSection.tickingList.clear(); + } + DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); + + // Synchronize to prevent further acquisitions + synchronized (lock) { + lock.acquire(); // Wait until we have the lock + lock.release(); + try { + sectionLock.writeLock().lock(); + if (this.getChunk() != nmsChunk) { + this.levelChunk = nmsChunk; + this.sections = null; + this.reset(); + } else if (existingSection != getSections(false)[getSectionIndex]) { + this.sections[getSectionIndex] = existingSection; + this.reset(); + } else if (!Arrays.equals( + update(getSectionIndex, new char[4096], true), + loadPrivately(layerNo) + )) { + this.reset(layerNo); + /*} else if (lock.isModified()) { + this.reset(layerNo);*/ + } + } finally { + sectionLock.writeLock().unlock(); + } + + PalettedContainer> biomeData = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); + + newSection = + PaperweightPlatformAdapter.newChunkSection( + layerNo, + this::loadPrivately, + setArr, + adapter, + biomeRegistry, + biomeData + ); + if (!PaperweightPlatformAdapter.setSectionAtomic( + levelChunkSections, + existingSection, + newSection, + getSectionIndex + )) { + LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, + getSectionIndex + ); + } else { + updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); + } + } + } + } + + Map heightMaps = set.getHeightMaps(); + for (Map.Entry entry : heightMaps.entrySet()) { + PaperweightGetBlocks.this.setHeightmapToGet(entry.getKey(), entry.getValue()); + } + PaperweightGetBlocks.this.setLightingToGet( + set.getLight(), + set.getMinSectionPosition(), + set.getMaxSectionPosition() + ); + PaperweightGetBlocks.this.setSkyLightingToGet( + set.getSkyLight(), + set.getMinSectionPosition(), + set.getMaxSectionPosition() + ); + + Runnable[] syncTasks = null; + + int bx = chunkX << 4; + int bz = chunkZ << 4; + + // Call beacon deactivate events here synchronously + // list will be null on spigot, so this is an implicit isPaper check + if (beacons != null && !beacons.isEmpty()) { + final List finalBeacons = beacons; + + syncTasks = new Runnable[4]; + + syncTasks[3] = () -> { + for (BlockEntity beacon : finalBeacons) { + BeaconBlockEntity.playSound(beacon.getLevel(), beacon.getBlockPos(), SoundEvents.BEACON_DEACTIVATE); + new BeaconDeactivatedEvent(CraftBlock.at(beacon.getLevel(), beacon.getBlockPos())).callEvent(); + } + }; + } + + Set entityRemoves = set.getEntityRemoves(); + if (entityRemoves != null && !entityRemoves.isEmpty()) { + if (syncTasks == null) { + syncTasks = new Runnable[3]; + } + + syncTasks[2] = () -> { + Set entitiesRemoved = new HashSet<>(); + final List entities = PaperweightPlatformAdapter.getEntities(nmsChunk); + + for (Entity entity : entities) { + UUID uuid = entity.getUUID(); + if (entityRemoves.contains(uuid)) { + if (createCopy) { + copy.storeEntity(entity); + } + removeEntity(entity); + entitiesRemoved.add(uuid); + entityRemoves.remove(uuid); + } + } + if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { + for (UUID uuid : entityRemoves) { + Entity entity = nmsWorld.getEntities().get(uuid); + if (entity != null) { + removeEntity(entity); + } + } + } + // Only save entities that were actually removed to history + set.getEntityRemoves().clear(); + set.getEntityRemoves().addAll(entitiesRemoved); + }; + } + + Set entities = set.getEntities(); + if (entities != null && !entities.isEmpty()) { + if (syncTasks == null) { + syncTasks = new Runnable[2]; + } + + syncTasks[1] = () -> { + Iterator iterator = entities.iterator(); + while (iterator.hasNext()) { + final CompoundTag nativeTag = iterator.next(); + final Map entityTagMap = nativeTag.getValue(); + final StringTag idTag = (StringTag) entityTagMap.get("Id"); + final ListTag posTag = (ListTag) entityTagMap.get("Pos"); + final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); + if (idTag == null || posTag == null || rotTag == null) { + LOGGER.error("Unknown entity tag: {}", nativeTag); + continue; + } + final double x = posTag.getDouble(0); + final double y = posTag.getDouble(1); + final double z = posTag.getDouble(2); + final float yaw = rotTag.getFloat(0); + final float pitch = rotTag.getFloat(1); + final String id = idTag.getValue(); + + EntityType type = EntityType.byString(id).orElse(null); + if (type != null) { + Entity entity = type.create(nmsWorld); + if (entity != null) { + final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( + nativeTag); + for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + entity.load(tag); + entity.absMoveTo(x, y, z, yaw, pitch); + entity.setUUID(nativeTag.getUUID()); + if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { + LOGGER.warn( + "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", + id, + nmsWorld.getWorld().getName(), + x, + y, + z + ); + // Unsuccessful create should not be saved to history + iterator.remove(); + } + } + } + } + }; + } + + // set tiles + Map tiles = set.getTiles(); + if (tiles != null && !tiles.isEmpty()) { + if (syncTasks == null) { + syncTasks = new Runnable[1]; + } + + syncTasks[0] = () -> { + for (final Map.Entry entry : tiles.entrySet()) { + final CompoundTag nativeTag = entry.getValue(); + final BlockVector3 blockHash = entry.getKey(); + final int x = blockHash.getX() + bx; + final int y = blockHash.getY(); + final int z = blockHash.getZ() + bz; + final BlockPos pos = new BlockPos(x, y, z); + + synchronized (nmsWorld) { + BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); + if (tileEntity == null || tileEntity.isRemoved()) { + nmsWorld.removeBlockEntity(pos); + tileEntity = nmsWorld.getBlockEntity(pos); + } + if (tileEntity != null) { + final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( + nativeTag); + tag.put("x", IntTag.valueOf(x)); + tag.put("y", IntTag.valueOf(y)); + tag.put("z", IntTag.valueOf(z)); + tileEntity.load(tag); + } + } + } + }; + } + + Runnable callback; + if (bitMask == 0 && biomes == null && !lightUpdate) { + callback = null; + } else { + int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; + boolean finalLightUpdate = lightUpdate; + callback = () -> { + // Set Modified + nmsChunk.setLightCorrect(true); // Set Modified + nmsChunk.mustNotSave = false; + nmsChunk.setUnsaved(true); + // send to player + if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { + this.send(finalMask, finalLightUpdate); + } + if (finalizer != null) { + finalizer.run(); + } + }; + } + if (syncTasks != null) { + QueueHandler queueHandler = Fawe.instance().getQueueHandler(); + Runnable[] finalSyncTasks = syncTasks; + + // Chain the sync tasks and the callback + Callable chain = () -> { + try { + // Run the sync tasks + for (Runnable task : finalSyncTasks) { + if (task != null) { + task.run(); + } + } + if (callback == null) { + if (finalizer != null) { + finalizer.run(); + } + return null; + } else { + return queueHandler.async(callback, null); + } + } catch (Throwable e) { + e.printStackTrace(); + throw e; + } + }; + //noinspection unchecked - required at compile time + return (T) (Future) queueHandler.sync(chain); + } else { + if (callback == null) { + if (finalizer != null) { + finalizer.run(); + } + } else { + callback.run(); + } + } + } + return null; + } catch (Throwable e) { + e.printStackTrace(); + return null; + } finally { + forceLoadSections = true; + } + } + + private void updateGet( + LevelChunk nmsChunk, + LevelChunkSection[] chunkSections, + LevelChunkSection section, + char[] arr, + int layer + ) { + try { + sectionLock.writeLock().lock(); + if (this.getChunk() != nmsChunk) { + this.levelChunk = nmsChunk; + this.sections = new LevelChunkSection[chunkSections.length]; + System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); + this.reset(); + } + if (this.sections == null) { + this.sections = new LevelChunkSection[chunkSections.length]; + System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); + } + if (this.sections[layer] != section) { + // Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords + this.sections[layer] = new LevelChunkSection[]{section}.clone()[0]; + } + } finally { + sectionLock.writeLock().unlock(); + } + this.blocks[layer] = arr; + } + + private char[] loadPrivately(int layer) { + layer -= getMinSectionPosition(); + if (super.sections[layer] != null) { + synchronized (super.sectionLocks[layer]) { + if (super.sections[layer].isFull() && super.blocks[layer] != null) { + char[] blocks = new char[4096]; + System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096); + return blocks; + } + } + } + return PaperweightGetBlocks.this.update(layer, null, true); + } + + @Override + public synchronized void send(int mask, boolean lighting) { + PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); + } + + /** + * Update a given (nullable) data array to the current data stored in the server's chunk, associated with this + * {@link PaperweightPlatformAdapter} instance. Not synchronised to the {@link PaperweightPlatformAdapter} instance as synchronisation + * is handled where necessary in the method, and should otherwise be handled correctly by this method's caller. + * + * @param layer layer index (0 may denote a negative layer in the world, e.g. at y=-32) + * @param data array to be updated/filled with data or null + * @param aggressive if the cached section array should be re-acquired. + * @return the given array to be filled with data, or a new array if null is given. + */ + @Override + @SuppressWarnings("unchecked") + public char[] update(int layer, char[] data, boolean aggressive) { + LevelChunkSection section = getSections(aggressive)[layer]; + // Section is null, return empty array + if (section == null) { + data = new char[4096]; + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); + return data; + } + if (data != null && data.length != 4096) { + data = new char[4096]; + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); + } + if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) { + data = new char[4096]; + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); + } + Semaphore lock = PaperweightPlatformAdapter.applyLock(section); + synchronized (lock) { + // Efficiently convert ChunkSection to raw data + try { + lock.acquire(); + + final PalettedContainer blocks = section.getStates(); + final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocks); + final BitStorage bits = (BitStorage) PaperweightPlatformAdapter.fieldStorage.get(dataObject); + + if (bits instanceof ZeroBitStorage) { + Arrays.fill(data, adapter.adaptToChar(blocks.get(0, 0, 0))); // get(int) is only public on paper + return data; + } + + final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get(dataObject); + + final int bitsPerEntry = bits.getBits(); + final long[] blockStates = bits.getRaw(); + + new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).toRaw(data); + + int num_palette; + if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { + num_palette = palette.getSize(); + } else { + // The section's palette is the global block palette. + for (int i = 0; i < 4096; i++) { + char paletteVal = data[i]; + char ordinal = adapter.ibdIDToOrdinal(paletteVal); + data[i] = ordinal; + } + return data; + } + + char[] paletteToOrdinal = FaweCache.INSTANCE.PALETTE_TO_BLOCK_CHAR.get(); + try { + if (num_palette != 1) { + for (int i = 0; i < num_palette; i++) { + char ordinal = ordinal(palette.valueFor(i), adapter); + paletteToOrdinal[i] = ordinal; + } + for (int i = 0; i < 4096; i++) { + char paletteVal = data[i]; + char val = paletteToOrdinal[paletteVal]; + if (val == Character.MAX_VALUE) { + val = ordinal(palette.valueFor(i), adapter); + paletteToOrdinal[i] = val; + } + data[i] = val; + } + } else { + char ordinal = ordinal(palette.valueFor(0), adapter); + Arrays.fill(data, ordinal); + } + } finally { + for (int i = 0; i < num_palette; i++) { + paletteToOrdinal[i] = Character.MAX_VALUE; + } + } + return data; + } catch (IllegalAccessException | InterruptedException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } finally { + lock.release(); + } + } + } + + private char ordinal(BlockState ibd, PaperweightFaweAdapter adapter) { + if (ibd == null) { + return BlockTypesCache.ReservedIDs.AIR; + } else { + return adapter.adaptToChar(ibd); + } + } + + public LevelChunkSection[] getSections(boolean force) { + force &= forceLoadSections; + sectionLock.readLock().lock(); + LevelChunkSection[] tmp = sections; + sectionLock.readLock().unlock(); + if (tmp == null || force) { + try { + sectionLock.writeLock().lock(); + tmp = sections; + if (tmp == null || force) { + LevelChunkSection[] chunkSections = getChunk().getSections(); + tmp = new LevelChunkSection[chunkSections.length]; + System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length); + sections = tmp; + } + } finally { + sectionLock.writeLock().unlock(); + } + } + return tmp; + } + + public LevelChunk getChunk() { + LevelChunk levelChunk = this.levelChunk; + if (levelChunk == null) { + synchronized (this) { + levelChunk = this.levelChunk; + if (levelChunk == null) { + this.levelChunk = levelChunk = ensureLoaded(this.serverLevel, chunkX, chunkZ); + } + } + } + return levelChunk; + } + + private void fillLightNibble(char[][] light, LightLayer lightLayer, int minSectionPosition, int maxSectionPosition) { + for (int Y = 0; Y <= maxSectionPosition - minSectionPosition; Y++) { + if (light[Y] == null) { + continue; + } + SectionPos sectionPos = SectionPos.of(levelChunk.getPos(), Y + minSectionPosition); + DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(lightLayer).getDataLayerData( + sectionPos); + if (dataLayer == null) { + byte[] LAYER_COUNT = new byte[2048]; + Arrays.fill(LAYER_COUNT, lightLayer == LightLayer.SKY ? (byte) 15 : (byte) 0); + dataLayer = new DataLayer(LAYER_COUNT); + ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( + lightLayer, + sectionPos, + dataLayer + ); + } + synchronized (dataLayer) { + for (int x = 0; x < 16; x++) { + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + int i = y << 8 | z << 4 | x; + if (light[Y][i] < 16) { + dataLayer.set(x, y, z, light[Y][i]); + } + } + } + } + } + } + } + + private PalettedContainer> setBiomesToPalettedContainer( + final BiomeType[][] biomes, + final int sectionIndex, + final PalettedContainerRO> data + ) { + PalettedContainer> biomeData; + if (data instanceof PalettedContainer> palettedContainer) { + biomeData = palettedContainer; + } else { + LOGGER.warn( + "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + + "type {} but got {}", + PalettedContainer.class.getSimpleName(), + data.getClass().getSimpleName() + ); + biomeData = data.recreate(); + } + BiomeType[] sectionBiomes; + if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { + return biomeData; + } + for (int y = 0, index = 0; y < 4; y++) { + for (int z = 0; z < 4; z++) { + for (int x = 0; x < 4; x++, index++) { + BiomeType biomeType = sectionBiomes[index]; + if (biomeType == null) { + continue; + } + biomeData.set( + x, + y, + z, + biomeHolderIdMap.byIdOrThrow(WorldEditPlugin + .getInstance() + .getBukkitImplAdapter() + .getInternalBiomeId(biomeType)) + ); + } + } + } + return biomeData; + } + + @Override + public boolean hasSection(int layer) { + layer -= getMinSectionPosition(); + return getSections(false)[layer] != null; + } + + @Override + @SuppressWarnings("unchecked") + public synchronized boolean trim(boolean aggressive) { + skyLight = new DataLayer[getSectionCount()]; + blockLight = new DataLayer[getSectionCount()]; + if (aggressive) { + sectionLock.writeLock().lock(); + sections = null; + levelChunk = null; + sectionLock.writeLock().unlock(); + return super.trim(true); + } else if (sections == null) { + // don't bother trimming if there are no sections stored. + return true; + } else { + for (int i = getMinSectionPosition(); i <= getMaxSectionPosition(); i++) { + int layer = i - getMinSectionPosition(); + if (!hasSection(i) || !super.sections[layer].isFull()) { + continue; + } + LevelChunkSection existing = getSections(true)[layer]; + try { + final PalettedContainer blocksExisting = existing.getStates(); + + final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocksExisting); + final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get( + dataObject); + int paletteSize; + + if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { + paletteSize = palette.getSize(); + } else { + super.trim(false, i); + continue; + } + if (paletteSize == 1) { + //If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks. + continue; + } + super.trim(false, i); + } catch (IllegalAccessException ignored) { + super.trim(false, i); + } + } + return true; + } + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java new file mode 100644 index 000000000..428161a48 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java @@ -0,0 +1,248 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; + +import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.queue.IBlocks; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import com.google.common.base.Suppliers; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.BlockVector3; +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.BlockTypesCache; +import net.minecraft.core.Holder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import org.apache.logging.log4j.Logger; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Future; + +public class PaperweightGetBlocks_Copy implements IChunkGet { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private final Map tiles = new HashMap<>(); + private final Set entities = new HashSet<>(); + private final char[][] blocks; + private final int minHeight; + private final int maxHeight; + final ServerLevel serverLevel; + final LevelChunk levelChunk; + private PalettedContainer>[] biomes = null; + + protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { + this.levelChunk = levelChunk; + this.serverLevel = levelChunk.level; + this.minHeight = serverLevel.getMinBuildHeight(); + this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. + this.blocks = new char[getSectionCount()][]; + } + + protected void storeTile(BlockEntity blockEntity) { + tiles.put( + BlockVector3.at( + blockEntity.getBlockPos().getX(), + blockEntity.getBlockPos().getY(), + blockEntity.getBlockPos().getZ() + ), + new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)) + ); + } + + @Override + public Map getTiles() { + return tiles; + } + + @Override + @Nullable + public CompoundTag getTile(int x, int y, int z) { + return tiles.get(BlockVector3.at(x, y, z)); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + protected void storeEntity(Entity entity) { + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); + entity.save(compoundTag); + entities.add((CompoundTag) adapter.toNative(compoundTag)); + } + + @Override + public Set getEntities() { + return this.entities; + } + + @Override + public CompoundTag getEntity(UUID uuid) { + for (CompoundTag tag : entities) { + if (uuid.equals(tag.getUUID())) { + return tag; + } + } + return null; + } + + @Override + public boolean isCreateCopy() { + return false; + } + + @Override + public void setCreateCopy(boolean createCopy) { + } + + @Override + public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { + } + + @Override + public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { + } + + @Override + public void setHeightmapToGet(HeightMapType type, int[] data) { + } + + @Override + public int getMaxY() { + return maxHeight; + } + + @Override + public int getMinY() { + return minHeight; + } + + @Override + public int getMaxSectionPosition() { + return maxHeight >> 4; + } + + @Override + public int getMinSectionPosition() { + return minHeight >> 4; + } + + @Override + public BiomeType getBiomeType(int x, int y, int z) { + Holder biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2); + return PaperweightPlatformAdapter.adapt(biome, serverLevel); + } + + @Override + public void removeSectionLighting(int layer, boolean sky) { + } + + @Override + public boolean trim(boolean aggressive, int layer) { + return false; + } + + @Override + public IBlocks reset() { + return null; + } + + @Override + public int getSectionCount() { + return serverLevel.getSectionsCount(); + } + + protected void storeSection(int layer, char[] data) { + blocks[layer] = data; + } + + protected void storeBiomes(int layer, PalettedContainerRO> biomeData) { + if (biomes == null) { + biomes = new PalettedContainer[getSectionCount()]; + } + if (biomeData instanceof PalettedContainer> palettedContainer) { + biomes[layer] = palettedContainer.copy(); + } else { + LOGGER.error( + "Cannot correctly save biomes to history. Expected class type {} but got {}", + PalettedContainer.class.getSimpleName(), + biomeData.getClass().getSimpleName() + ); + } + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + BlockState state = BlockTypesCache.states[get(x, y, z)]; + return state.toBaseBlock(this, x, y, z); + } + + @Override + public boolean hasSection(int layer) { + layer -= getMinSectionPosition(); + return blocks[layer] != null; + } + + @Override + public char[] load(int layer) { + layer -= getMinSectionPosition(); + return blocks[layer]; + } + + @Override + public char[] loadIfPresent(int layer) { + layer -= getMinSectionPosition(); + return blocks[layer]; + } + + @Override + public BlockState getBlock(int x, int y, int z) { + return BlockTypesCache.states[get(x, y, z)]; + } + + @Override + public int getSkyLight(int x, int y, int z) { + return 0; + } + + @Override + public int getEmittedLight(int x, int y, int z) { + return 0; + } + + @Override + public int[] getHeightMap(HeightMapType type) { + return new int[0]; + } + + @Override + public > T call(IChunkSet set, Runnable finalize) { + return null; + } + + public char get(int x, int y, int z) { + final int layer = (y >> 4) - getMinSectionPosition(); + final int index = (y & 15) << 8 | z << 4 | x; + return blocks[layer][index]; + } + + + @Override + public boolean trim(boolean aggressive) { + return false; + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightMapChunkUtil.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightMapChunkUtil.java new file mode 100644 index 000000000..e6501086e --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightMapChunkUtil.java @@ -0,0 +1,34 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; + +import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; + +//TODO un-very-break-this +public class PaperweightMapChunkUtil extends MapChunkUtil { + + public PaperweightMapChunkUtil() throws NoSuchFieldException { + fieldX = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("TWO_MEGABYTES", "a")); + fieldZ = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("x", "a")); + fieldBitMask = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("z", "b")); + fieldHeightMap = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("heightmaps", "b")); + fieldChunkData = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("chunkData", "c")); + fieldBlockEntities = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("buffer", "c")); + fieldFull = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("blockEntitiesData", "d")); + fieldX.setAccessible(true); + fieldZ.setAccessible(true); + fieldBitMask.setAccessible(true); + fieldHeightMap.setAccessible(true); + fieldChunkData.setAccessible(true); + fieldBlockEntities.setAccessible(true); + fieldFull.setAccessible(true); + } + + @Override + public ClientboundLevelChunkWithLightPacket createPacket() { + // TODO ??? return new ClientboundLevelChunkPacket(); + throw new UnsupportedOperationException(); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java new file mode 100644 index 000000000..9ab6b0602 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java @@ -0,0 +1,719 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; + +import com.destroystokyo.paper.util.maplist.EntityList; +import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; +import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; +import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.util.MathMan; +import com.fastasyncworldedit.core.util.ReflectionUtils; +import com.fastasyncworldedit.core.util.TaskManager; +import com.mojang.datafixers.util.Either; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +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.BlockTypesCache; +import io.papermc.lib.PaperLib; +import io.papermc.paper.world.ChunkEntitySlices; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.IdMap; +import net.minecraft.core.Registry; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.TicketType; +import net.minecraft.util.BitStorage; +import net.minecraft.util.ExceptionCollector; +import net.minecraft.util.SimpleBitStorage; +import net.minecraft.util.ThreadingDetector; +import net.minecraft.util.Unit; +import net.minecraft.util.ZeroBitStorage; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.GlobalPalette; +import net.minecraft.world.level.chunk.HashMapPalette; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.LinearPalette; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.SingleValuePalette; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import org.apache.logging.log4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_20_R2.CraftChunk; +import sun.misc.Unsafe; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Function; + +import static java.lang.invoke.MethodType.methodType; +import static net.minecraft.core.registries.Registries.BIOME; + +public final class PaperweightPlatformAdapter extends NMSAdapter { + + public static final Field fieldData; + + public static final Constructor dataConstructor; + + public static final Field fieldStorage; + public static final Field fieldPalette; + + private static final Field fieldTickingFluidCount; + private static final Field fieldTickingBlockCount; + private static final Field fieldNonEmptyBlockCount; + + private static final MethodHandle methodGetVisibleChunk; + + private static final Field fieldThreadingDetector; + private static final Field fieldLock; + + private static final MethodHandle methodRemoveGameEventListener; + private static final MethodHandle methodremoveTickingBlockEntity; + + /* + * This is a workaround for the changes from https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/1fddefce1cdce44010927b888432bf70c0e88cde#src/main/java/org/bukkit/craftbukkit/CraftChunk.java + * and is only needed to support 1.19.4 versions before *and* after this change. + */ + private static final MethodHandle CRAFT_CHUNK_GET_HANDLE; + + private static final Field fieldRemove; + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + static final boolean POST_CHUNK_REWRITE; + private static Method PAPER_CHUNK_GEN_ALL_ENTITIES; + private static Field LEVEL_CHUNK_ENTITIES; + private static Field SERVER_LEVEL_ENTITY_MANAGER; + + static { + final MethodHandles.Lookup lookup = MethodHandles.lookup(); + try { + fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d")); + fieldData.setAccessible(true); + + Class dataClazz = fieldData.getType(); + dataConstructor = dataClazz.getDeclaredConstructors()[0]; + dataConstructor.setAccessible(true); + + fieldStorage = dataClazz.getDeclaredField(Refraction.pickName("storage", "b")); + fieldStorage.setAccessible(true); + fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c")); + fieldPalette.setAccessible(true); + + fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "g")); + fieldTickingFluidCount.setAccessible(true); + fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); + fieldTickingBlockCount.setAccessible(true); + fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e")); + fieldNonEmptyBlockCount.setAccessible(true); + + Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( + "getVisibleChunkIfPresent", + "b" + ), long.class); + getVisibleChunkIfPresent.setAccessible(true); + methodGetVisibleChunk = lookup.unreflect(getVisibleChunkIfPresent); + + if (!PaperLib.isPaper()) { + fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); + fieldThreadingDetector.setAccessible(true); + fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); + fieldLock.setAccessible(true); + } else { + // in paper, the used methods are synchronized properly + fieldThreadingDetector = null; + fieldLock = null; + } + + Method removeGameEventListener = LevelChunk.class.getDeclaredMethod( + Refraction.pickName("removeGameEventListener", "a"), + BlockEntity.class, + ServerLevel.class + ); + removeGameEventListener.setAccessible(true); + methodRemoveGameEventListener = lookup.unreflect(removeGameEventListener); + + Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod( + Refraction.pickName( + "removeBlockEntityTicker", + "l" + ), BlockPos.class + ); + removeBlockEntityTicker.setAccessible(true); + methodremoveTickingBlockEntity = lookup.unreflect(removeBlockEntityTicker); + + fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "q")); + fieldRemove.setAccessible(true); + + boolean chunkRewrite; + try { + ServerLevel.class.getDeclaredMethod("getEntityLookup"); + chunkRewrite = true; + PAPER_CHUNK_GEN_ALL_ENTITIES = ChunkEntitySlices.class.getDeclaredMethod("getAllEntities"); + PAPER_CHUNK_GEN_ALL_ENTITIES.setAccessible(true); + } catch (NoSuchMethodException ignored) { + chunkRewrite = false; + } + try { + // Paper - Pre-Chunk-Update + LEVEL_CHUNK_ENTITIES = LevelChunk.class.getDeclaredField("entities"); + LEVEL_CHUNK_ENTITIES.setAccessible(true); + } catch (NoSuchFieldException ignored) { + } + try { + // Non-Paper + SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "M")); + SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true); + } catch (NoSuchFieldException ignored) { + } + POST_CHUNK_REWRITE = chunkRewrite; + } catch (RuntimeException | Error e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + MethodHandle craftChunkGetHandle; + final MethodType type = methodType(LevelChunk.class); + try { + craftChunkGetHandle = lookup.findVirtual(CraftChunk.class, "getHandle", type); + } catch (NoSuchMethodException | IllegalAccessException e) { + try { + final MethodType newType = methodType(ChunkAccess.class, ChunkStatus.class); + craftChunkGetHandle = lookup.findVirtual(CraftChunk.class, "getHandle", newType); + craftChunkGetHandle = MethodHandles.insertArguments(craftChunkGetHandle, 1, ChunkStatus.FULL); + } catch (NoSuchMethodException | IllegalAccessException ex) { + throw new RuntimeException(ex); + } + } + CRAFT_CHUNK_GET_HANDLE = craftChunkGetHandle; + } + + static boolean setSectionAtomic( + LevelChunkSection[] sections, + LevelChunkSection expected, + LevelChunkSection value, + int layer + ) { + if (layer >= 0 && layer < sections.length) { + return ReflectionUtils.compareAndSet(sections, expected, value, layer); + } + return false; + } + + // There is no point in having a functional semaphore for paper servers. + private static final ThreadLocal SEMAPHORE_THREAD_LOCAL = + ThreadLocal.withInitial(() -> new DelegateSemaphore(1, null)); + + static DelegateSemaphore applyLock(LevelChunkSection section) { + if (PaperLib.isPaper()) { + return SEMAPHORE_THREAD_LOCAL.get(); + } + try { + synchronized (section) { + PalettedContainer blocks = section.getStates(); + ThreadingDetector currentThreadingDetector = (ThreadingDetector) fieldThreadingDetector.get(blocks); + synchronized (currentThreadingDetector) { + Semaphore currentLock = (Semaphore) fieldLock.get(currentThreadingDetector); + if (currentLock instanceof DelegateSemaphore delegateSemaphore) { + return delegateSemaphore; + } + DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); + fieldLock.set(currentThreadingDetector, newLock); + return newLock; + } + } + } catch (Throwable e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) { + if (!PaperLib.isPaper()) { + LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false); + if (nmsChunk != null) { + return nmsChunk; + } + if (Fawe.isMainThread()) { + return serverLevel.getChunk(chunkX, chunkZ); + } + } else { + LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ); + if (nmsChunk != null) { + addTicket(serverLevel, chunkX, chunkZ); + return nmsChunk; + } + nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ); + if (nmsChunk != null) { + addTicket(serverLevel, chunkX, chunkZ); + return nmsChunk; + } + // Avoid "async" methods from the main thread. + if (Fawe.isMainThread()) { + return serverLevel.getChunk(chunkX, chunkZ); + } + CompletableFuture future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true); + try { + CraftChunk chunk; + try { + chunk = (CraftChunk) future.get(10, TimeUnit.SECONDS); + } catch (TimeoutException e) { + String world = serverLevel.getWorld().getName(); + // We've already taken 10 seconds we can afford to wait a little here. + boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null); + if (loaded) { + LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world); + // Retry chunk load + chunk = (CraftChunk) serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true).get(); + } else { + throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!"); + } + } + addTicket(serverLevel, chunkX, chunkZ); + return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk); + } catch (Throwable e) { + e.printStackTrace(); + } + } + return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)); + } + + private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) { + // Ensure chunk is definitely loaded before applying a ticket + io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel + .getChunkSource() + .addRegionTicket(TicketType.UNLOAD_COOLDOWN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE)); + } + + public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) { + ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap; + try { + return (ChunkHolder) methodGetVisibleChunk.invoke(chunkMap, ChunkPos.asLong(chunkX, chunkZ)); + } catch (Throwable thr) { + throw new RuntimeException(thr); + } + } + + @SuppressWarnings("deprecation") + public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) { + ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); + if (chunkHolder == null) { + return; + } + ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ); + LevelChunk levelChunk; + if (PaperLib.isPaper()) { + // getChunkAtIfLoadedImmediately is paper only + levelChunk = nmsWorld + .getChunkSource() + .getChunkAtIfLoadedImmediately(chunkX, chunkZ); + } else { + levelChunk = ((Optional) ((Either) chunkHolder + .getTickingChunkFuture() // method is not present with new paper chunk system + .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left()) + .orElse(null); + } + if (levelChunk == null) { + return; + } + TaskManager.taskManager().task(() -> { + ClientboundLevelChunkWithLightPacket packet; + if (PaperLib.isPaper()) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + // last false is to not bother with x-ray + ); + } else { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); + } + nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); + }); + } + + private static List nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) { + return serverLevel.getChunkSource().chunkMap.getPlayers(coordIntPair, false); + } + + /* + NMS conversion + */ + public static LevelChunkSection newChunkSection( + final int layer, + final char[] blocks, + CachedBukkitAdapter adapter, + Registry biomeRegistry, + @Nullable PalettedContainer> biomes + ) { + return newChunkSection(layer, null, blocks, adapter, biomeRegistry, biomes); + } + + public static LevelChunkSection newChunkSection( + final int layer, + final Function get, + char[] set, + CachedBukkitAdapter adapter, + Registry biomeRegistry, + @Nullable PalettedContainer> biomes + ) { + if (set == null) { + return newChunkSection(layer, biomeRegistry, biomes); + } + final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); + final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); + final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get(); + final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get(); + try { + int num_palette; + if (get == null) { + num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter, null); + } else { + num_palette = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, get, set, adapter, null); + } + + int bitsPerEntry = MathMan.log2nlz(num_palette - 1); + if (bitsPerEntry > 0 && bitsPerEntry < 5) { + bitsPerEntry = 4; + } else if (bitsPerEntry > 8) { + bitsPerEntry = MathMan.log2nlz(Block.BLOCK_STATE_REGISTRY.size() - 1); + } + + int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes + final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); + final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong); + + if (num_palette == 1) { + for (int i = 0; i < blockBitArrayEnd; i++) { + blockStates[i] = 0; + } + } else { + final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntryNonZero, 4096, blockStates); + bitArray.fromRaw(blocksCopy); + } + + final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd); + final BitStorage nmsBits; + if (bitsPerEntry == 0) { + nmsBits = new ZeroBitStorage(4096); + } else { + nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits); + } + List palette; + if (bitsPerEntry < 9) { + palette = new ArrayList<>(); + for (int i = 0; i < num_palette; i++) { + int ordinal = paletteToBlock[i]; + blockToPalette[ordinal] = Integer.MAX_VALUE; + final BlockState state = BlockTypesCache.states[ordinal]; + palette.add(((PaperweightBlockMaterial) state.getMaterial()).getState()); + } + } else { + palette = List.of(); + } + + // Create palette with data + @SuppressWarnings("deprecation") // constructor is deprecated on paper, but needed to keep compatibility with spigot + final PalettedContainer blockStatePalettedContainer = + new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, + PalettedContainer.Strategy.SECTION_STATES, + PalettedContainer.Strategy.SECTION_STATES.getConfiguration(Block.BLOCK_STATE_REGISTRY, bitsPerEntry), + nmsBits, + palette + ); + if (biomes == null) { + IdMap> biomeHolderIdMap = biomeRegistry.asHolderIdMap(); + biomes = new PalettedContainer<>( + biomeHolderIdMap, + biomeHolderIdMap.byIdOrThrow(WorldEditPlugin + .getInstance() + .getBukkitImplAdapter() + .getInternalBiomeId( + BiomeTypes.PLAINS)), + PalettedContainer.Strategy.SECTION_BIOMES + ); + } + + return new LevelChunkSection(blockStatePalettedContainer, biomes); + } catch (final Throwable e) { + throw e; + } finally { + Arrays.fill(blockToPalette, Integer.MAX_VALUE); + Arrays.fill(paletteToBlock, Integer.MAX_VALUE); + Arrays.fill(blockStates, 0); + Arrays.fill(blocksCopy, 0); + } + } + + @SuppressWarnings("deprecation") // Only deprecated in paper + private static LevelChunkSection newChunkSection( + int layer, + Registry biomeRegistry, + @Nullable PalettedContainer> biomes + ) { + if (biomes == null) { + return new LevelChunkSection(biomeRegistry); + } + PalettedContainer dataPaletteBlocks = new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), + PalettedContainer.Strategy.SECTION_STATES + ); + return new LevelChunkSection(dataPaletteBlocks, biomes); + } + + /** + * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. + */ + public static PalettedContainer> getBiomePalettedContainer( + BiomeType[] biomes, + IdMap> biomeRegistry + ) { + if (biomes == null) { + return null; + } + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + // Don't stream this as typically will see 1-4 biomes; stream overhead is large for the small length + Map> palette = new HashMap<>(); + for (BiomeType biomeType : new LinkedList<>(Arrays.asList(biomes))) { + Holder biome; + if (biomeType == null) { + biome = biomeRegistry.byId(adapter.getInternalBiomeId(BiomeTypes.PLAINS)); + } else { + biome = biomeRegistry.byId(adapter.getInternalBiomeId(biomeType)); + } + palette.put(biomeType, biome); + } + int biomeCount = palette.size(); + int bitsPerEntry = MathMan.log2nlz(biomeCount - 1); + Object configuration = PalettedContainer.Strategy.SECTION_STATES.getConfiguration( + new FakeIdMapBiome(biomeCount), + bitsPerEntry + ); + if (bitsPerEntry > 3) { + bitsPerEntry = MathMan.log2nlz(biomeRegistry.size() - 1); + } + PalettedContainer> biomePalettedContainer = new PalettedContainer<>( + biomeRegistry, + biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), + PalettedContainer.Strategy.SECTION_BIOMES + ); + + final Palette> biomePalette; + if (bitsPerEntry == 0) { + biomePalette = new SingleValuePalette<>( + biomePalettedContainer.registry, + biomePalettedContainer, + new ArrayList<>(palette.values()) // Must be modifiable + ); + } else if (bitsPerEntry == 4) { + biomePalette = LinearPalette.create( + 4, + biomePalettedContainer.registry, + biomePalettedContainer, + new ArrayList<>(palette.values()) // Must be modifiable + ); + } else if (bitsPerEntry < 9) { + biomePalette = HashMapPalette.create( + bitsPerEntry, + biomePalettedContainer.registry, + biomePalettedContainer, + new ArrayList<>(palette.values()) // Must be modifiable + ); + } else { + biomePalette = GlobalPalette.create( + bitsPerEntry, + biomePalettedContainer.registry, + biomePalettedContainer, + null // unused + ); + } + + int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes + final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); + final int arrayLength = MathMan.ceilZero(64f / blocksPerLong); + + + BitStorage bitStorage = bitsPerEntry == 0 ? new ZeroBitStorage(64) : new SimpleBitStorage( + bitsPerEntry, + 64, + new long[arrayLength] + ); + + try { + Object data = dataConstructor.newInstance(configuration, bitStorage, biomePalette); + fieldData.set(biomePalettedContainer, data); + int index = 0; + for (int y = 0; y < 4; y++) { + for (int z = 0; z < 4; z++) { + for (int x = 0; x < 4; x++, index++) { + BiomeType biomeType = biomes[index]; + if (biomeType == null) { + continue; + } + Holder biome = biomeRegistry.byId(WorldEditPlugin + .getInstance() + .getBukkitImplAdapter() + .getInternalBiomeId(biomeType)); + if (biome == null) { + continue; + } + biomePalettedContainer.set(x, y, z, biome); + } + } + } + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + return biomePalettedContainer; + } + + public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException { + fieldTickingFluidCount.setShort(section, (short) 0); + fieldTickingBlockCount.setShort(section, (short) 0); + } + + public static BiomeType adapt(Holder biome, LevelAccessor levelAccessor) { + final Registry biomeRegistry = levelAccessor.registryAccess().registryOrThrow(BIOME); + if (biomeRegistry.getKey(biome.value()) == null) { + return biomeRegistry.asHolderIdMap().getId(biome) == -1 ? BiomeTypes.OCEAN + : null; + } + return BiomeTypes.get(biome.unwrapKey().orElseThrow().location().toString()); + } + + static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { + try { + if (levelChunk.loaded || levelChunk.level.isClientSide()) { + BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos()); + if (blockEntity != null) { + if (!levelChunk.level.isClientSide) { + methodRemoveGameEventListener.invoke(levelChunk, beacon, levelChunk.level); + } + fieldRemove.set(beacon, true); + } + } + methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos()); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + + static List getEntities(LevelChunk chunk) { + ExceptionCollector collector = new ExceptionCollector<>(); + if (PaperLib.isPaper()) { + if (POST_CHUNK_REWRITE) { + try { + //noinspection unchecked + return (List) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level.getEntityLookup().getChunk(chunk.locX, chunk.locZ)); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=true]", e); + } + } + try { + EntityList entityList = (EntityList) LEVEL_CHUNK_ENTITIES.get(chunk); + return List.of(entityList.getRawData()); + } catch (IllegalAccessException e) { + collector.add(new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=false]", e)); + // fall through + } + } + try { + //noinspection unchecked + return ((PersistentEntitySectionManager) (SERVER_LEVEL_ENTITY_MANAGER.get(chunk.level))).getEntities(chunk.getPos()); + } catch (IllegalAccessException e) { + collector.add(new RuntimeException("Failed to lookup entities [PAPER=false]", e)); + } + collector.throwIfPresent(); + return List.of(); + } + + record FakeIdMapBlock(int size) implements IdMap { + + @Override + public int getId(final net.minecraft.world.level.block.state.BlockState entry) { + return 0; + } + + @Nullable + @Override + public net.minecraft.world.level.block.state.BlockState byId(final int index) { + return null; + } + + @Nonnull + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + + } + + record FakeIdMapBiome(int size) implements IdMap { + + @Override + public int getId(final Biome entry) { + return 0; + } + + @Nullable + @Override + public Biome byId(final int index) { + return null; + } + + @Nonnull + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPostProcessor.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPostProcessor.java new file mode 100644 index 000000000..5fafdc439 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPostProcessor.java @@ -0,0 +1,175 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; + +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.extent.processor.ProcessorScope; +import com.fastasyncworldedit.core.queue.IBatchProcessor; +import com.fastasyncworldedit.core.queue.IChunk; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import com.fastasyncworldedit.core.registry.state.PropertyKey; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.Fluids; + +import javax.annotation.Nullable; + +public class PaperweightPostProcessor implements IBatchProcessor { + + @Override + public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) { + return set; + } + + @SuppressWarnings("deprecation") + @Override + public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) { + boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS; + // The PostProcessor shouldn't be added, but just in case + if (!tickFluid) { + return; + } + PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet; + layer: + for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) { + char[] set = iChunkSet.loadIfPresent(layer); + if (set == null) { + // No edit means no need to process + continue; + } + char[] get = null; + for (int i = 0; i < 4096; i++) { + char ordinal = set[i]; + char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__; + boolean fromGet = false; // Used for liquids + if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { + if (get == null) { + get = getBlocks.load(layer); + } + // If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't + // actually being set + if (get == null) { + continue layer; + } + fromGet = true; + ordinal = replacedOrdinal = get[i]; + } + if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { + continue; + } else if (!fromGet) { // if fromGet, don't do the same again + if (get == null) { + get = getBlocks.load(layer); + } + replacedOrdinal = get[i]; + } + boolean ticking = BlockTypesCache.ticking[ordinal]; + boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal]; + boolean replacedWasLiquid = false; + BlockState replacedState = null; + if (!ticking) { + // If the block being replaced was not ticking, it cannot be a liquid + if (!replacedWasTicking) { + continue; + } + // If the block being replaced is not fluid, we do not need to worry + if (!(replacedWasLiquid = + (replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) { + continue; + } + } + BlockState state = BlockState.getFromOrdinal(ordinal); + boolean liquid = state.getMaterial().isLiquid(); + int x = i & 15; + int y = (i >> 8) & 15; + int z = (i >> 4) & 15; + BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z); + if (liquid || replacedWasLiquid) { + if (liquid) { + addFluid(getBlocks.serverLevel, state, position); + continue; + } + // If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this + // may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up + // being ticked anyway. We only need it to be "hit" once. + if (!wasAdjacentToWater(get, set, i, x, y, z)) { + continue; + } + addFluid(getBlocks.serverLevel, replacedState, position); + } + } + } + } + + @Nullable + @Override + public Extent construct(final Extent child) { + throw new UnsupportedOperationException("Processing only"); + } + + @Override + public ProcessorScope getScope() { + return ProcessorScope.READING_SET_BLOCKS; + } + + private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) { + if (set == null || get == null) { + return false; + } + char ordinal; + char reserved = BlockTypesCache.ReservedIDs.__RESERVED__; + if (x > 0 && set[i - 1] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) { + return true; + } + } + if (x < 15 && set[i + 1] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) { + return true; + } + } + if (z > 0 && set[i - 16] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) { + return true; + } + } + if (z < 15 && set[i + 16] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) { + return true; + } + } + if (y > 0 && set[i - 256] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) { + return true; + } + } + if (y < 15 && set[i + 256] != reserved) { + return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal); + } + return false; + } + + @SuppressWarnings("deprecation") + private boolean isFluid(char ordinal) { + return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid(); + } + + @SuppressWarnings("deprecation") + private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) { + Fluid type; + if (replacedState.getBlockType() == BlockTypes.LAVA) { + type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA; + } else { + type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER; + } + serverLevel.scheduleTick( + position, + type, + type.getTickDelay(serverLevel) + ); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java new file mode 100644 index 000000000..6c6527c02 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java @@ -0,0 +1,205 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; + +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter; +import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; +import com.fastasyncworldedit.core.queue.IQueueChunk; +import com.fastasyncworldedit.core.queue.IQueueExtent; +import com.fastasyncworldedit.core.util.MathMan; +import com.fastasyncworldedit.core.util.TaskManager; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.longs.LongArraySet; +import it.unimi.dsi.fastutil.longs.LongIterator; +import it.unimi.dsi.fastutil.longs.LongSet; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.TicketType; +import net.minecraft.util.Unit; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.ChunkStatus; +import org.apache.logging.log4j.Logger; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; +import java.util.function.IntConsumer; + +public class PaperweightStarlightRelighter implements Relighter { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static final int CHUNKS_PER_BATCH = 1024; // 32 * 32 + private static final int CHUNKS_PER_BATCH_SQRT_LOG2 = 5; // for shifting + + private static final TicketType FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); + private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkStatus.getDistance(ChunkStatus.LIGHT); + + + private final ServerLevel serverLevel; + private final ReentrantLock lock = new ReentrantLock(); + private final Long2ObjectLinkedOpenHashMap regions = new Long2ObjectLinkedOpenHashMap<>(); + private final ReentrantLock areaLock = new ReentrantLock(); + private final NMSRelighter delegate; + + @SuppressWarnings("rawtypes") + public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { + this.serverLevel = serverLevel; + this.delegate = new NMSRelighter(queue); + } + + @Override + public boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask) { + areaLock.lock(); + try { + long key = MathMan.pairInt(cx >> CHUNKS_PER_BATCH_SQRT_LOG2, cz >> CHUNKS_PER_BATCH_SQRT_LOG2); + // TODO probably submit here already if chunks.size == CHUNKS_PER_BATCH? + LongSet chunks = this.regions.computeIfAbsent(key, k -> new LongArraySet(CHUNKS_PER_BATCH >> 2)); + chunks.add(ChunkPos.asLong(cx, cz)); + } finally { + areaLock.unlock(); + } + return true; + } + + @Override + public void addLightUpdate(int x, int y, int z) { + delegate.addLightUpdate(x, y, z); + } + + /* + * This method is called "recursively", iterating and removing elements + * from the regions linked map. This way, chunks are loaded in batches to avoid + * OOMEs. + */ + @Override + public void fixLightingSafe(boolean sky) { + this.areaLock.lock(); + try { + if (regions.isEmpty()) { + return; + } + LongSet first = regions.removeFirst(); + fixLighting(first, () -> fixLightingSafe(true)); + } finally { + this.areaLock.unlock(); + } + } + + /* + * Processes a set of chunks and runs an action afterwards. + * The action is run async, the chunks are partly processed on the main thread + * (as required by the server). + */ + private void fixLighting(LongSet chunks, Runnable andThen) { + // convert from long keys to ChunkPos + Set coords = new HashSet<>(); + LongIterator iterator = chunks.iterator(); + while (iterator.hasNext()) { + coords.add(new ChunkPos(iterator.nextLong())); + } + TaskManager.taskManager().task(() -> { + // trigger chunk load and apply ticket on main thread + List> futures = new ArrayList<>(); + for (ChunkPos pos : coords) { + futures.add(serverLevel.getWorld().getChunkAtAsync(pos.x, pos.z) + .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( + FAWE_TICKET, + pos, + LIGHT_LEVEL, + Unit.INSTANCE + )) + ); + } + // collect futures and trigger relight once all chunks are loaded + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(v -> + invokeRelight( + coords, + c -> { + }, // no callback for single chunks required + i -> { + if (i != coords.size()) { + LOGGER.warn("Processed {} chunks instead of {}", i, coords.size()); + } + // post process chunks on main thread + TaskManager.taskManager().task(() -> postProcessChunks(coords)); + // call callback on our own threads + TaskManager.taskManager().async(andThen); + } + ) + ); + }); + } + + private void invokeRelight( + Set coords, + Consumer chunkCallback, + IntConsumer processCallback + ) { + try { + serverLevel.getChunkSource().getLightEngine().relight(coords, chunkCallback, processCallback); + } catch (Exception e) { + LOGGER.error("Error occurred on relighting", e); + } + } + + /* + * Allow the server to unload the chunks again. + * Also, if chunk packets are sent delayed, we need to do that here + */ + private void postProcessChunks(Set coords) { + boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING; + for (ChunkPos pos : coords) { + int x = pos.x; + int z = pos.z; + if (delay) { // we still need to send the block changes of that chunk + PaperweightPlatformAdapter.sendChunk(serverLevel, x, z, false); + } + serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE); + } + } + + @Override + public void clear() { + + } + + @Override + public void removeLighting() { + this.delegate.removeLighting(); + } + + @Override + public void fixBlockLighting() { + fixLightingSafe(true); + } + + @Override + public void fixSkyLighting() { + fixLightingSafe(true); + } + + @Override + public boolean isEmpty() { + return true; + } + + @Override + public ReentrantLock getLock() { + return this.lock; + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public void close() throws Exception { + fixLightingSafe(true); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighterFactory.java new file mode 100644 index 000000000..4e5b9b7ff --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighterFactory.java @@ -0,0 +1,28 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; + +import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; +import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; +import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; +import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; +import com.fastasyncworldedit.core.queue.IQueueChunk; +import com.fastasyncworldedit.core.queue.IQueueExtent; +import com.sk89q.worldedit.world.World; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; + +import javax.annotation.Nonnull; + +public class PaperweightStarlightRelighterFactory implements RelighterFactory { + + @Override + public @Nonnull + @SuppressWarnings("rawtypes") + Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { + org.bukkit.World w = Bukkit.getWorld(world.getName()); + if (w == null) { + return NullRelighter.INSTANCE; + } + return new PaperweightStarlightRelighter(((CraftWorld) w).getHandle(), queue); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/nbt/PaperweightLazyCompoundTag.java new file mode 100644 index 000000000..911da046a --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/nbt/PaperweightLazyCompoundTag.java @@ -0,0 +1,161 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.nbt; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.LazyCompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import net.minecraft.nbt.NumericTag; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +public class PaperweightLazyCompoundTag extends LazyCompoundTag { + + private final Supplier compoundTagSupplier; + private CompoundTag compoundTag; + + public PaperweightLazyCompoundTag(Supplier compoundTagSupplier) { + super(new HashMap<>()); + this.compoundTagSupplier = compoundTagSupplier; + } + + public PaperweightLazyCompoundTag(net.minecraft.nbt.CompoundTag compoundTag) { + this(() -> compoundTag); + } + + public net.minecraft.nbt.CompoundTag get() { + return compoundTagSupplier.get(); + } + + @Override + @SuppressWarnings("unchecked") + public Map getValue() { + if (compoundTag == null) { + compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); + } + return compoundTag.getValue(); + } + + @Override + public CompoundBinaryTag asBinaryTag() { + getValue(); + return compoundTag.asBinaryTag(); + } + + public boolean containsKey(String key) { + return compoundTagSupplier.get().contains(key); + } + + public byte[] getByteArray(String key) { + return compoundTagSupplier.get().getByteArray(key); + } + + public byte getByte(String key) { + return compoundTagSupplier.get().getByte(key); + } + + public double getDouble(String key) { + return compoundTagSupplier.get().getDouble(key); + } + + public double asDouble(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof NumericTag numTag) { + return numTag.getAsDouble(); + } + return 0; + } + + public float getFloat(String key) { + return compoundTagSupplier.get().getFloat(key); + } + + public int[] getIntArray(String key) { + return compoundTagSupplier.get().getIntArray(key); + } + + public int getInt(String key) { + return compoundTagSupplier.get().getInt(key); + } + + public int asInt(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof NumericTag numTag) { + return numTag.getAsInt(); + } + return 0; + } + + @SuppressWarnings("unchecked") + public List getList(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof net.minecraft.nbt.ListTag nbtList) { + ArrayList list = new ArrayList<>(); + for (net.minecraft.nbt.Tag elem : nbtList) { + if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { + list.add(new PaperweightLazyCompoundTag(compoundTag)); + } else { + list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem)); + } + } + return list; + } + return Collections.emptyList(); + } + + @SuppressWarnings("unchecked") + public ListTag getListTag(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof net.minecraft.nbt.ListTag) { + return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag); + } + return new ListTag(StringTag.class, Collections.emptyList()); + } + + @SuppressWarnings("unchecked") + public List getList(String key, Class listType) { + ListTag listTag = getListTag(key); + if (listTag.getType().equals(listType)) { + return (List) listTag.getValue(); + } else { + return Collections.emptyList(); + } + } + + public long[] getLongArray(String key) { + return compoundTagSupplier.get().getLongArray(key); + } + + public long getLong(String key) { + return compoundTagSupplier.get().getLong(key); + } + + public long asLong(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof NumericTag numTag) { + return numTag.getAsLong(); + } + return 0; + } + + public short getShort(String key) { + return compoundTagSupplier.get().getShort(key); + } + + public String getString(String key) { + return compoundTagSupplier.get().getString(key); + } + + @Override + public String toString() { + return compoundTagSupplier.get().toString(); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/regen/PaperweightRegen.java new file mode 100644 index 000000000..2ec8e6e41 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/regen/PaperweightRegen.java @@ -0,0 +1,591 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.regen; + +import com.fastasyncworldedit.bukkit.adapter.Regenerator; +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.queue.IChunkCache; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.util.ReflectionUtils; +import com.fastasyncworldedit.core.util.TaskManager; +import com.google.common.collect.ImmutableList; +import com.mojang.datafixers.util.Either; +import com.mojang.serialization.Lifecycle; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.PaperweightGetBlocks; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.io.file.SafeFiles; +import com.sk89q.worldedit.world.RegenOptions; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.util.thread.ProcessorHandle; +import net.minecraft.util.thread.ProcessorMailbox; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.LevelSettings; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.biome.FixedBiomeSource; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.levelgen.WorldOptions; +import net.minecraft.world.level.levelgen.blending.BlendingData; +import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; +import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; +import net.minecraft.world.level.storage.LevelStorageSource; +import net.minecraft.world.level.storage.PrimaryLevelData; +import org.apache.logging.log4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.craftbukkit.v1_20_R2.CraftServer; +import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R2.generator.CustomChunkGenerator; +import org.bukkit.generator.BiomeProvider; +import org.bukkit.generator.BlockPopulator; + +import javax.annotation.Nullable; +import java.lang.reflect.Field; +import java.nio.file.Path; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.OptionalLong; +import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.function.BooleanSupplier; +import java.util.function.Supplier; + +import static net.minecraft.core.registries.Registries.BIOME; + +public class PaperweightRegen extends Regenerator { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private static final Field serverWorldsField; + private static final Field paperConfigField; + private static final Field flatBedrockField; + private static final Field generatorSettingFlatField; + private static final Field generatorSettingBaseSupplierField; + private static final Field delegateField; + private static final Field chunkSourceField; + private static final Field generatorStructureStateField; + private static final Field ringPositionsField; + private static final Field hasGeneratedPositionsField; + + //list of chunk stati in correct order without FULL + private static final Map chunkStati = new LinkedHashMap<>(); + + static { + chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing + chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps + chunkStati.put( + ChunkStatus.STRUCTURE_REFERENCES, + Concurrency.FULL + ); // structure refs: radius 8, but only writes to current chunk + chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // biomes: radius 0 + chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8 + chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE + chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results + /*chunkStati.put( + ChunkStatus.LIQUID_CARVERS, + Concurrency.NONE + ); // liquid carvers: radius 0, but RADIUS and FULL change results*/ + chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps + chunkStati.put( + ChunkStatus.LIGHT, + Concurrency.FULL + ); // light: radius 1, but no writes to other chunks, only current chunk + chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0 + // chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0 + + try { + serverWorldsField = CraftServer.class.getDeclaredField("worlds"); + serverWorldsField.setAccessible(true); + + Field tmpPaperConfigField; + Field tmpFlatBedrockField; + try { //only present on paper + tmpPaperConfigField = Level.class.getDeclaredField("paperConfig"); + tmpPaperConfigField.setAccessible(true); + + tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock"); + tmpFlatBedrockField.setAccessible(true); + } catch (Exception e) { + tmpPaperConfigField = null; + tmpFlatBedrockField = null; + } + paperConfigField = tmpPaperConfigField; + flatBedrockField = tmpFlatBedrockField; + + generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName( + "settings", "e")); + generatorSettingBaseSupplierField.setAccessible(true); + + generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "d")); + generatorSettingFlatField.setAccessible(true); + + delegateField = CustomChunkGenerator.class.getDeclaredField("delegate"); + delegateField.setAccessible(true); + + chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "I")); + chunkSourceField.setAccessible(true); + + generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "v")); + generatorStructureStateField.setAccessible(true); + + ringPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(Refraction.pickName("ringPositions", "g")); + ringPositionsField.setAccessible(true); + + hasGeneratedPositionsField = ChunkGeneratorStructureState.class.getDeclaredField( + Refraction.pickName("hasGeneratedPositions", "h") + ); + hasGeneratedPositionsField.setAccessible(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + //runtime + private ServerLevel originalServerWorld; + private ServerChunkCache originalChunkProvider; + private ServerLevel freshWorld; + private ServerChunkCache freshChunkProvider; + private LevelStorageSource.LevelStorageAccess session; + private StructureTemplateManager structureTemplateManager; + private ThreadedLevelLightEngine threadedLevelLightEngine; + private ChunkGenerator chunkGenerator; + + private Path tempDir; + + private boolean generateFlatBedrock = false; + + public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) { + super(originalBukkitWorld, region, target, options); + } + + @Override + protected boolean prepare() { + this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle(); + originalChunkProvider = originalServerWorld.getChunkSource(); + + //flat bedrock? (only on paper) + if (paperConfigField != null) { + try { + generateFlatBedrock = flatBedrockField.getBoolean(paperConfigField.get(originalServerWorld)); + } catch (Exception ignored) { + } + } + + seed = options.getSeed().orElse(originalServerWorld.getSeed()); + chunkStati.forEach((s, c) -> super.chunkStatuses.put(new ChunkStatusWrap(s), c)); + + return true; + } + + @Override + @SuppressWarnings("unchecked") + protected boolean initNewWorld() throws Exception { + //world folder + tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen"); + + //prepare for world init (see upstream implementation for reference) + org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment(); + org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator(); + LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir); + ResourceKey levelStemResourceKey = getWorldDimKey(environment); + session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey); + PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData; + + MinecraftServer server = originalServerWorld.getCraftServer().getServer(); + WorldOptions originalOpts = originalWorldData.worldGenOptions(); + WorldOptions newOpts = options.getSeed().isPresent() + ? originalOpts.withSeed(OptionalLong.of(seed)) + : originalOpts; + LevelSettings newWorldSettings = new LevelSettings( + "faweregentempworld", + originalWorldData.settings.gameType(), + originalWorldData.settings.hardcore(), + originalWorldData.settings.difficulty(), + originalWorldData.settings.allowCommands(), + originalWorldData.settings.gameRules(), + originalWorldData.settings.getDataConfiguration() + ); + + PrimaryLevelData.SpecialWorldProperty specialWorldProperty = + originalWorldData.isFlatWorld() + ? PrimaryLevelData.SpecialWorldProperty.FLAT + : originalWorldData.isDebugWorld() + ? PrimaryLevelData.SpecialWorldProperty.DEBUG + : PrimaryLevelData.SpecialWorldProperty.NONE; + PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable()); + + BiomeProvider biomeProvider = getBiomeProvider(); + + + //init world + freshWorld = Fawe.instance().getQueueHandler().sync((Supplier) () -> new ServerLevel( + server, + server.executor, + session, + newWorldData, + originalServerWorld.dimension(), + DedicatedServer.getServer().registryAccess().registry(Registries.LEVEL_STEM).orElseThrow() + .getOrThrow(levelStemResourceKey), + new RegenNoOpWorldLoadListener(), + originalServerWorld.isDebug(), + seed, + ImmutableList.of(), + false, + originalServerWorld.getRandomSequences(), + environment, + generator, + biomeProvider + ) { + + private final Holder singleBiome = options.hasBiomeType() ? DedicatedServer.getServer().registryAccess() + .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( + WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) + ) : null; + + @Override + public void tick(BooleanSupplier shouldKeepTicking) { //no ticking + } + + @Override + public Holder getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { + if (options.hasBiomeType()) { + return singleBiome; + } + return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome( + biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler() + ); + } + }).get(); + freshWorld.noSave = true; + removeWorldFromWorldsMap(); + newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name + if (paperConfigField != null) { + paperConfigField.set(freshWorld, originalServerWorld.paperConfig()); + } + + ChunkGenerator originalGenerator = originalChunkProvider.getGenerator(); + if (originalGenerator instanceof FlatLevelSource flatLevelSource) { + FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings(); + chunkGenerator = new FlatLevelSource(generatorSettingFlat); + } else if (originalGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + Holder generatorSettingBaseSupplier = (Holder) generatorSettingBaseSupplierField.get( + originalGenerator); + BiomeSource biomeSource; + if (options.hasBiomeType()) { + + biomeSource = new FixedBiomeSource( + DedicatedServer.getServer().registryAccess() + .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( + WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) + ) + ); + } else { + biomeSource = originalGenerator.getBiomeSource(); + } + chunkGenerator = new NoiseBasedChunkGenerator( + biomeSource, + generatorSettingBaseSupplier + ); + } else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) { + chunkGenerator = customChunkGenerator.getDelegate(); + } else { + LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName()); + return false; + } + if (generator != null) { + chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator); + generateConcurrent = generator.isParallelCapable(); + } +// chunkGenerator.conf = freshWorld.spigotConfig; - Does not exist anymore, may need to be re-addressed + + freshChunkProvider = new ServerChunkCache( + freshWorld, + session, + server.getFixerUpper(), + server.getStructureManager(), + server.executor, + chunkGenerator, + freshWorld.spigotConfig.viewDistance, + freshWorld.spigotConfig.simulationDistance, + server.forceSynchronousWrites(), + new RegenNoOpWorldLoadListener(), + (chunkCoordIntPair, state) -> { + }, + () -> server.overworld().getDataStorage() + ) { + // redirect to LevelChunks created in #createChunks + @Override + public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean create) { + ChunkAccess chunkAccess = getChunkAt(x, z); + if (chunkAccess == null && create) { + chunkAccess = createChunk(getProtoChunkAt(x, z)); + } + return chunkAccess; + } + }; + + if (seed == originalOpts.seed() && !options.hasBiomeType()) { + // Optimisation for needless ring position calculation when the seed and biome is the same. + ChunkGeneratorStructureState state = (ChunkGeneratorStructureState) generatorStructureStateField.get(originalChunkProvider.chunkMap); + boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(state); + if (hasGeneratedPositions) { + Map>> origPositions = + (Map>>) ringPositionsField.get(state); + Map>> copy = new Object2ObjectArrayMap<>( + origPositions); + ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get(freshChunkProvider.chunkMap); + ringPositionsField.set(newState, copy); + hasGeneratedPositionsField.setBoolean(newState, true); + } + } + + + chunkSourceField.set(freshWorld, freshChunkProvider); + //let's start then + structureTemplateManager = server.getStructureManager(); + threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider); + + return true; + } + + @Override + protected void cleanup() { + try { + session.close(); + } catch (Exception ignored) { + } + + //shutdown chunk provider + try { + Fawe.instance().getQueueHandler().sync(() -> { + try { + freshChunkProvider.close(false); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } catch (Exception ignored) { + } + + //remove world from server + try { + Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap); + } catch (Exception ignored) { + } + + //delete directory + try { + SafeFiles.tryHardToDeleteDir(tempDir); + } catch (Exception ignored) { + } + } + + @Override + protected ProtoChunk createProtoChunk(int x, int z) { + return new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld, + this.freshWorld.registryAccess().registryOrThrow(BIOME), null + ); + } + + @Override + protected LevelChunk createChunk(ProtoChunk protoChunk) { + return new LevelChunk( + freshWorld, + protoChunk, + null // we don't want to add entities + ); + } + + @Override + protected ChunkStatusWrap getFullChunkStatus() { + return new ChunkStatusWrap(ChunkStatus.FULL); + } + + @Override + protected List getBlockPopulators() { + return originalServerWorld.getWorld().getPopulators(); + } + + @Override + protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) { + // BlockPopulator#populate has to be called synchronously for TileEntity access + TaskManager.taskManager().task(() -> { + final CraftWorld world = freshWorld.getWorld(); + final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ); + blockPopulator.populate(world, random, chunk); + }); + } + + @Override + protected IChunkCache initSourceQueueCache() { + return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) { + @Override + public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) { + return getChunkAt(x, z); + } + }; + } + + //util + @SuppressWarnings("unchecked") + private void removeWorldFromWorldsMap() { + Fawe.instance().getQueueHandler().sync(() -> { + try { + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); + map.remove("faweregentempworld"); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + }); + } + + private ResourceKey getWorldDimKey(org.bukkit.World.Environment env) { + return switch (env) { + case NETHER -> LevelStem.NETHER; + case THE_END -> LevelStem.END; + default -> LevelStem.OVERWORLD; + }; + } + + private static class RegenNoOpWorldLoadListener implements ChunkProgressListener { + + private RegenNoOpWorldLoadListener() { + } + + @Override + public void updateSpawnPos(ChunkPos spawnPos) { + } + + @Override + public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) { + } + + @Override + public void start() { + + } + + @Override + public void stop() { + } + + // TODO Paper only(?) @Override + public void setChunkRadius(int radius) { + } + + } + + private class FastProtoChunk extends ProtoChunk { + + public FastProtoChunk( + final ChunkPos pos, + final UpgradeData upgradeData, + final LevelHeightAccessor world, + final Registry biomeRegistry, + @Nullable final BlendingData blendingData + ) { + super(pos, upgradeData, world, biomeRegistry, blendingData); + } + + // avoid warning on paper + + // compatibility with spigot + + public boolean generateFlatBedrock() { + return generateFlatBedrock; + } + + // no one will ever see the entities! + @Override + public List getEntities() { + return Collections.emptyList(); + } + + } + + protected class ChunkStatusWrap extends ChunkStatusWrapper { + + private final ChunkStatus chunkStatus; + + public ChunkStatusWrap(ChunkStatus chunkStatus) { + this.chunkStatus = chunkStatus; + } + + @Override + public int requiredNeighborChunkRadius() { + return chunkStatus.getRange(); + } + + @Override + public String name() { + return chunkStatus.toString(); + } + + @Override + public CompletableFuture processChunk(List accessibleChunks) { + return chunkStatus.generate( + Runnable::run, // TODO revisit, we might profit from this somehow? + freshWorld, + chunkGenerator, + structureTemplateManager, + threadedLevelLightEngine, + c -> CompletableFuture.completedFuture(Either.left(c)), + accessibleChunks + ); + } + + } + + /** + * A light engine that does nothing. As light is calculated after pasting anyway, we can avoid + * work this way. + */ + static class NoOpLightEngine extends ThreadedLevelLightEngine { + + private static final ProcessorMailbox MAILBOX = ProcessorMailbox.create(task -> { + }, "fawe-no-op"); + private static final ProcessorHandle> HANDLE = ProcessorHandle.of("fawe-no-op", m -> { + }); + + public NoOpLightEngine(final ServerChunkCache chunkProvider) { + super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE); + } + + @Override + public CompletableFuture lightChunk(final ChunkAccess chunk, final boolean excludeBlocks) { + return CompletableFuture.completedFuture(chunk); + } + + } + +} diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index 4f7211db5..710c68212 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -206,7 +206,7 @@ tasks { versionNumber.set("${project.version}") versionType.set("release") uploadFile.set(file("build/libs/${rootProject.name}-Bukkit-${project.version}.jar")) - gameVersions.addAll(listOf("1.20.1", "1.20", "1.19.4", "1.18.2", "1.17.1", "1.16.5")) + gameVersions.addAll(listOf("1.20.2", "1.20.1", "1.20", "1.19.4", "1.18.2", "1.17.1", "1.16.5")) loaders.addAll(listOf("paper", "spigot")) changelog.set("The changelog is available on GitHub: https://github.com/IntellectualSites/" + "FastAsyncWorldEdit/releases/tag/${project.version}") diff --git a/worldedit-core/build.gradle.kts b/worldedit-core/build.gradle.kts index a58230b2c..d9794d9f6 100644 --- a/worldedit-core/build.gradle.kts +++ b/worldedit-core/build.gradle.kts @@ -12,7 +12,7 @@ applyPlatformAndCoreConfiguration() dependencies { constraints { implementation(libs.snakeyaml) { - version { strictly("2.0") } + version { strictly("2.2") } because("Bukkit provides SnakeYaml") } } From 828308b71dff7601ddcd40f578125cdc2bbbeb12 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Fri, 29 Sep 2023 22:51:11 +0200 Subject: [PATCH 018/466] Release 2.8.0 --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index ed699857f..ee21f4b08 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.7.2") +var rootVersion by extra("2.8.0") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s-%s", rootVersion, buildNumber) +version = String.format("%s", rootVersion) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From a7f1d94b6f2f35088509bd435a1e42820ca789fb Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Fri, 29 Sep 2023 23:17:00 +0200 Subject: [PATCH 019/466] Back to snapshot for development --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index ee21f4b08..9cc6dee0f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.8.0") +var rootVersion by extra("2.8.1") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s", rootVersion) +version = String.format("%s-%s", rootVersion, buildNumber) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From 8bfb4f31acf18509cb911ceaa1b7ed6143664743 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 10:06:25 +0200 Subject: [PATCH 020/466] Update plugin xyz.jpenilla.run-paper to v2.2.0 (#2441) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 9cc6dee0f..44fa18649 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,7 +7,7 @@ import xyz.jpenilla.runpaper.task.RunServer plugins { id("io.github.gradle-nexus.publish-plugin") version "1.3.0" - id("xyz.jpenilla.run-paper") version "2.1.0" + id("xyz.jpenilla.run-paper") version "2.2.0" } if (!File("$rootDir/.git").exists()) { From c8069bbdb4dbea72563ce8a3ac743fe5307957aa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 10:18:32 +0200 Subject: [PATCH 021/466] Update dependency com.zaxxer:SparseBitSet to v1.3 (#2439) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1fe45859b..ffb24f7e9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,7 +19,7 @@ plotsquared = "7.0.0" # Third party bstats = "3.0.2" -sparsebitset = "1.2" +sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.14.0" adventure-bukkit = "4.3.0" From fca775ee14e282900fcf51cbc7c93a8e1edae4f1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 10:18:43 +0200 Subject: [PATCH 022/466] Update dependency net.kyori:adventure-platform-bukkit to v4.3.1 (#2438) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ffb24f7e9..589d2827b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -22,7 +22,7 @@ bstats = "3.0.2" sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.14.0" -adventure-bukkit = "4.3.0" +adventure-bukkit = "4.3.1" checkerqual = "3.38.0" truezip = "6.8.4" auto-value = "1.10.2" From f2ca272fb4ae38699a03afc9b4ac143919b71a2f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 11:26:45 +0200 Subject: [PATCH 023/466] Update antlr4 to v4.13.1 (#2436) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 589d2827b..3774e0d6a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ auto-value = "1.10.2" findbugs = "3.0.2" rhino-runtime = "1.7.14" zstd-jni = "1.4.8-1" # Not latest as it can be difficult to obtain latest ZSTD libs -antlr4 = "4.13.0" +antlr4 = "4.13.1" json-simple = "1.1.1" jlibnoise = "1.0.0" jchronic = "0.2.4a" From a88b4c7e32bb456cd9537df396f580fcb44c2f24 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 11:26:58 +0200 Subject: [PATCH 024/466] Update dependency com.palmergames.bukkit.towny:towny to v0.99.5.20 (#2437) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3774e0d6a..13066707a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "16.18.1" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.99.5.16" +towny = "0.99.5.20" plotsquared = "7.0.0" # Third party From c7465cc156d10a2ade20dd3eb9eae2927a6fa3fa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 12:00:08 +0200 Subject: [PATCH 025/466] Update actions/checkout action to v4 (#2442) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build-pr.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/upload-release-assets.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index 11f0d1d5d..98319f7d2 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -9,7 +9,7 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest] steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@v1 - name: Setup Java diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 65555631f..6cda7331f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@v1 - name: Setup Java diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f4287607f..a0cd830bd 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -19,7 +19,7 @@ jobs: language: ['java'] steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Java uses: actions/setup-java@v3 with: diff --git a/.github/workflows/upload-release-assets.yml b/.github/workflows/upload-release-assets.yml index e93fc35c5..cb1d0a9d1 100644 --- a/.github/workflows/upload-release-assets.yml +++ b/.github/workflows/upload-release-assets.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@v1 - name: Setup Java From 66c2dc3edaaa71cf0c9f7e71e6f3f6ff06eb628f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 12:00:16 +0200 Subject: [PATCH 026/466] Update dependency com.zaxxer:SparseBitSet to v1.3 (#2440) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index 710c68212..ead334bf4 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -186,7 +186,7 @@ tasks.named("shadowJar") { include(dependency("net.kyori:adventure-nbt:4.14.0")) } relocate("com.zaxxer", "com.fastasyncworldedit.core.math") { - include(dependency("com.zaxxer:SparseBitSet:1.2")) + include(dependency("com.zaxxer:SparseBitSet:1.3")) } relocate("org.anarres", "com.fastasyncworldedit.core.internal.io") { include(dependency("org.anarres:parallelgzip:1.0.5")) From dccf82ab1b5dbaad48bba1c01af85cc1462ed6e2 Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 2 Oct 2023 20:36:21 +0100 Subject: [PATCH 027/466] fix: set villager offers temporarily to save NBT without sending event (#2357) --- .../adapter/ext/fawe/PaperweightAdapter.java | 5 ++- .../v1_17_R1_2/PaperweightFaweAdapter.java | 6 +--- .../fawe/v1_17_R1_2/PaperweightGetBlocks.java | 4 +-- .../v1_17_R1_2/PaperweightGetBlocks_Copy.java | 2 +- .../PaperweightPlatformAdapter.java | 31 ++++++++++++++++++ .../ext/fawe/v1_18_R2/PaperweightAdapter.java | 5 ++- .../fawe/v1_18_R2/PaperweightFaweAdapter.java | 6 +--- .../fawe/v1_18_R2/PaperweightGetBlocks.java | 4 +-- .../v1_18_R2/PaperweightGetBlocks_Copy.java | 2 +- .../v1_18_R2/PaperweightPlatformAdapter.java | 32 ++++++++++++++++++- .../ext/fawe/v1_19_R3/PaperweightAdapter.java | 5 ++- .../fawe/v1_19_R3/PaperweightFaweAdapter.java | 6 +--- .../fawe/v1_19_R3/PaperweightGetBlocks.java | 4 +-- .../v1_19_R3/PaperweightGetBlocks_Copy.java | 2 +- .../v1_19_R3/PaperweightPlatformAdapter.java | 31 ++++++++++++++++++ .../ext/fawe/v1_20_R1/PaperweightAdapter.java | 8 +++-- .../fawe/v1_20_R1/PaperweightFaweAdapter.java | 6 +--- .../fawe/v1_20_R1/PaperweightGetBlocks.java | 31 +++++++++++++++--- .../v1_20_R1/PaperweightGetBlocks_Copy.java | 2 +- .../v1_20_R1/PaperweightPlatformAdapter.java | 27 ++++++++++++++++ 20 files changed, 177 insertions(+), 42 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java index f369b8458..52974fb02 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java @@ -38,6 +38,7 @@ import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.PaperweightFaweAdapter; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.PaperweightPlatformAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extent.Extent; @@ -288,7 +289,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter getParent() { return parent; @@ -367,7 +363,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); - readEntityIntoTag(mcEntity, minecraftTag); + PaperweightPlatformAdapter.readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java index aab9e5aa7..d7a1be074 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java @@ -374,7 +374,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc public Iterator iterator() { Iterable result = entities.stream().map(input -> { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - input.save(tag); + PaperweightPlatformAdapter.readEntityIntoTag(input, tag); return (CompoundTag) adapter.toNative(tag); }).collect(Collectors.toList()); return result.iterator(); @@ -394,7 +394,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @SuppressWarnings("rawtypes") public synchronized > T call(IChunkSet set, Runnable finalizer) { forceLoadSections = false; - copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + copy = createCopy ? new PaperweightGetBlocks_Copy(getChunk()) : null; try { ServerLevel nmsWorld = serverLevel; LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java index de431c718..65b16ee3b 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java @@ -74,7 +74,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { protected void storeEntity(Entity entity) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); + PaperweightPlatformAdapter.readEntityIntoTag(entity, compoundTag); entities.add((CompoundTag) adapter.toNative(compoundTag)); } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java index 0854fc7ad..16dfd7bd8 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java @@ -34,6 +34,8 @@ import net.minecraft.server.level.TicketType; import net.minecraft.util.BitStorage; import net.minecraft.util.Unit; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.npc.AbstractVillager; +import net.minecraft.world.item.trading.MerchantOffers; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.biome.Biome; @@ -90,6 +92,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldGameEventDispatcherSections; private static final MethodHandle methodremoveBlockEntityTicker; + private static final Field fieldOffers; + private static final MerchantOffers OFFERS = new MerchantOffers(); + private static final Field fieldRemove; private static final Logger LOGGER = LogManagerCompat.getLogger(); @@ -145,6 +150,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p")); fieldRemove.setAccessible(true); + + fieldOffers = AbstractVillager.class.getDeclaredField(Refraction.pickName("offers", "bU")); + fieldOffers.setAccessible(true); } catch (RuntimeException e) { throw e; } catch (Throwable rethrow) { @@ -492,4 +500,27 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return chunk.level.entityManager.getEntities(chunk.getPos()); } + public static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { + boolean isVillager = entity instanceof AbstractVillager && !Fawe.isMainThread(); + boolean unset = false; + if (isVillager) { + try { + if (fieldOffers.get(entity) != null) { + fieldOffers.set(entity, OFFERS); + unset = true; + } + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to set offers field to villager to avoid async catcher.", e); + } + } + entity.save(compoundTag); + if (unset) { + try { + fieldOffers.set(entity, null); + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to set offers field to null again on villager.", e); + } + } + } + } diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2/PaperweightAdapter.java index 47389b357..1edc3be1d 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2/PaperweightAdapter.java @@ -34,6 +34,7 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.PaperweightPlatformAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extent.Extent; @@ -270,7 +271,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter getParent() { return parent; @@ -360,7 +356,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); - readEntityIntoTag(mcEntity, minecraftTag); + PaperweightPlatformAdapter.readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java index 91a5abede..fba567a5b 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java @@ -368,7 +368,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc public Iterator iterator() { Iterable result = entities.stream().map(input -> { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - input.save(tag); + PaperweightPlatformAdapter.readEntityIntoTag(input, tag); return (CompoundTag) adapter.toNative(tag); }).collect(Collectors.toList()); return result.iterator(); @@ -388,7 +388,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @SuppressWarnings("rawtypes") public synchronized > T call(IChunkSet set, Runnable finalizer) { forceLoadSections = false; - copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + copy = createCopy ? new PaperweightGetBlocks_Copy(getChunk()) : null; try { ServerLevel nmsWorld = serverLevel; LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks_Copy.java index 991c3d1f9..5c68de6fe 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks_Copy.java @@ -76,7 +76,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { protected void storeEntity(Entity entity) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); + PaperweightPlatformAdapter.readEntityIntoTag(entity, compoundTag); entities.add((CompoundTag) adapter.toNative(compoundTag)); } diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightPlatformAdapter.java index 1075694b4..06281908d 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightPlatformAdapter.java @@ -35,6 +35,8 @@ import net.minecraft.util.ThreadingDetector; import net.minecraft.util.Unit; import net.minecraft.util.ZeroBitStorage; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.npc.AbstractVillager; +import net.minecraft.world.item.trading.MerchantOffers; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.biome.Biome; @@ -98,6 +100,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodremoveTickingBlockEntity; + private static final Field fieldOffers; + private static final MerchantOffers OFFERS = new MerchantOffers(); + private static final Field fieldRemove; private static final Logger LOGGER = LogManagerCompat.getLogger(); @@ -158,6 +163,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p")); fieldRemove.setAccessible(true); + + fieldOffers = AbstractVillager.class.getDeclaredField(Refraction.pickName("offers", "bW")); + fieldOffers.setAccessible(true); } catch (RuntimeException e) { throw e; } catch (Throwable rethrow) { @@ -571,7 +579,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return BiomeTypes.get(biome.unwrapKey().orElseThrow().location().toString()); } - @SuppressWarnings("unchecked") static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { try { // Do the method ourselves to avoid trying to reflect generic method parameters @@ -595,6 +602,29 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return chunk.level.entityManager.getEntities(chunk.getPos()); } + public static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { + boolean isVillager = entity instanceof AbstractVillager && !Fawe.isMainThread(); + boolean unset = false; + if (isVillager) { + try { + if (fieldOffers.get(entity) != null) { + fieldOffers.set(entity, OFFERS); + unset = true; + } + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to set offers field to villager to avoid async catcher.", e); + } + } + entity.save(compoundTag); + if (unset) { + try { + fieldOffers.set(entity, null); + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to set offers field to null again on villager.", e); + } + } + } + record FakeIdMapBlock(int size) implements IdMap { @Override diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java index e106c7d56..22c5a07b2 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java @@ -35,6 +35,7 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.PaperweightPlatformAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extent.Extent; @@ -276,7 +277,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter getParent() { return parent; @@ -321,7 +317,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); - readEntityIntoTag(mcEntity, minecraftTag); + PaperweightPlatformAdapter.readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java index c715e5fc2..0840b4aac 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java @@ -369,7 +369,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc public Iterator iterator() { Iterable result = entities.stream().map(input -> { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - input.save(tag); + PaperweightPlatformAdapter.readEntityIntoTag(input, tag); return (CompoundTag) adapter.toNative(tag); }).collect(Collectors.toList()); return result.iterator(); @@ -389,7 +389,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @SuppressWarnings("rawtypes") public synchronized > T call(IChunkSet set, Runnable finalizer) { forceLoadSections = false; - copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + copy = createCopy ? new PaperweightGetBlocks_Copy(getChunk()) : null; try { ServerLevel nmsWorld = serverLevel; LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java index b6557ef0b..0c5d62692 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java @@ -80,7 +80,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { protected void storeEntity(Entity entity) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); + PaperweightPlatformAdapter.readEntityIntoTag(entity, compoundTag); entities.add((CompoundTag) adapter.toNative(compoundTag)); } diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java index 16210db38..d0ce1c555 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java @@ -38,6 +38,8 @@ import net.minecraft.util.ThreadingDetector; import net.minecraft.util.Unit; import net.minecraft.util.ZeroBitStorage; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.npc.AbstractVillager; +import net.minecraft.world.item.trading.MerchantOffers; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.biome.Biome; @@ -105,6 +107,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodremoveTickingBlockEntity; + private static final Field fieldOffers; + private static final MerchantOffers OFFERS = new MerchantOffers(); + private static final Field fieldRemove; private static final Logger LOGGER = LogManagerCompat.getLogger(); @@ -196,6 +201,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } catch (NoSuchFieldException ignored) { } POST_CHUNK_REWRITE = chunkRewrite; + + fieldOffers = AbstractVillager.class.getDeclaredField(Refraction.pickName("offers", "bT")); + fieldOffers.setAccessible(true); } catch (RuntimeException | Error e) { throw e; } catch (Exception e) { @@ -656,6 +664,29 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return List.of(); } + public static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { + boolean isVillager = entity instanceof AbstractVillager && !Fawe.isMainThread(); + boolean unset = false; + if (isVillager) { + try { + if (fieldOffers.get(entity) != null) { + fieldOffers.set(entity, OFFERS); + unset = true; + } + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to set offers field to villager to avoid async catcher.", e); + } + } + entity.save(compoundTag); + if (unset) { + try { + fieldOffers.set(entity, null); + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to set offers field to null again on villager.", e); + } + } + } + record FakeIdMapBlock(int size) implements IdMap { @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java index 428176c5f..b40c12b1a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java @@ -27,7 +27,6 @@ import com.google.common.collect.Sets; import com.google.common.util.concurrent.Futures; import com.mojang.datafixers.util.Either; import com.mojang.serialization.Lifecycle; -import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.NBTConstants; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; @@ -35,6 +34,7 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.PaperweightPlatformAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extent.Extent; @@ -138,6 +138,7 @@ import org.bukkit.generator.ChunkGenerator; import org.spigotmc.SpigotConfig; import org.spigotmc.WatchdogThread; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -159,7 +160,6 @@ import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; -import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; @@ -277,7 +277,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter getParent() { return parent; @@ -321,7 +317,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); - readEntityIntoTag(mcEntity, minecraftTag); + PaperweightPlatformAdapter.readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java index 08d2f1069..e0e746109 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java @@ -29,7 +29,11 @@ import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BlockTypesCache; import io.papermc.lib.PaperLib; import io.papermc.paper.event.block.BeaconDeactivatedEvent; -import net.minecraft.core.*; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.IdMap; +import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.nbt.IntTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; @@ -42,7 +46,14 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.entity.BeaconBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.*; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.HashMapPalette; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.LinearPalette; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.lighting.LevelLightEngine; import org.apache.logging.log4j.Logger; @@ -52,7 +63,17 @@ import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; import javax.annotation.Nonnull; -import java.util.*; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.Semaphore; @@ -347,7 +368,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc public Iterator iterator() { Iterable result = entities.stream().map(input -> { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - input.save(tag); + PaperweightPlatformAdapter.readEntityIntoTag(input, tag); return (CompoundTag) adapter.toNative(tag); }).collect(Collectors.toList()); return result.iterator(); @@ -367,7 +388,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @SuppressWarnings("rawtypes") public synchronized > T call(IChunkSet set, Runnable finalizer) { forceLoadSections = false; - copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + copy = createCopy ? new PaperweightGetBlocks_Copy(getChunk()) : null; try { ServerLevel nmsWorld = serverLevel; LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java index 7a387a887..a23000249 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java @@ -80,7 +80,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { protected void storeEntity(Entity entity) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); + PaperweightPlatformAdapter.readEntityIntoTag(entity, compoundTag); entities.add((CompoundTag) adapter.toNative(compoundTag)); } diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java index 2fe34894d..8083e3fde 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java @@ -38,6 +38,9 @@ import net.minecraft.util.ThreadingDetector; import net.minecraft.util.Unit; import net.minecraft.util.ZeroBitStorage; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.npc.AbstractVillager; +import net.minecraft.world.entity.npc.Villager; +import net.minecraft.world.item.trading.MerchantOffers; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.biome.Biome; @@ -108,6 +111,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodremoveTickingBlockEntity; + private static final Field fieldOffers; + private static final MerchantOffers OFFERS = new MerchantOffers(); + /* * This is a workaround for the changes from https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/1fddefce1cdce44010927b888432bf70c0e88cde#src/main/java/org/bukkit/craftbukkit/CraftChunk.java * and is only needed to support 1.19.4 versions before *and* after this change. @@ -205,6 +211,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } catch (NoSuchFieldException ignored) { } POST_CHUNK_REWRITE = chunkRewrite; + + fieldOffers = AbstractVillager.class.getDeclaredField(Refraction.pickName("offers", "bU")); + fieldOffers.setAccessible(true); } catch (RuntimeException | Error e) { throw e; } catch (Exception e) { @@ -674,6 +683,24 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return List.of(); } + public static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { + boolean unset = false; + if (entity instanceof Villager villager && !Fawe.isMainThread()) { + try { + if (fieldOffers.get(entity) == null) { + villager.setOffers(OFFERS); + unset = true; + } + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to set offers field to villager to avoid async catcher.", e); + } + } + entity.save(compoundTag); + if (unset) { + ((Villager) entity).setOffers(null); + } + } + record FakeIdMapBlock(int size) implements IdMap { @Override From 971559ec23dc16e4a5be27379481e9ad7d269502 Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 4 Oct 2023 09:39:14 +0100 Subject: [PATCH 028/466] feat: fake the copied biomes (#2359) --- .../sk89q/worldedit/function/operation/ForwardExtentCopy.java | 4 ++++ 1 file changed, 4 insertions(+) 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 9959c9d67..99ee125ed 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 @@ -446,6 +446,10 @@ public class ForwardExtentCopy implements Operation { } affectedBlocks += blockCopy.getAffected(); + if (copyingBiomes) { + // We know biomes will have happened unless something else has gone wrong. Just calculate it. + affectedBiomeCols += source.fullySupports3DBiomes() ? (getAffected() >> 2) : (region.getWidth() * region.getLength()); + } //FAWE end return null; } From aaa00ea71ec99df548f2331567c717b4bec26aca Mon Sep 17 00:00:00 2001 From: BlockyTheDev <86119630+BlockyTheDev@users.noreply.github.com> Date: Wed, 4 Oct 2023 11:04:35 +0200 Subject: [PATCH 029/466] Addresses issues related to maven publish scm block (#2435) * Addresses issues related to maven publish scm block - Fixes https://github.com/IntellectualSites/FastAsyncWorldEdit/issues/2423 - Fixes https://github.com/IntellectualSites/FastAsyncWorldEdit/issues/2422 - Resolves https://github.com/IntellectualSites/FastAsyncWorldEdit/issues/2421 * Fix wrong change --- buildSrc/src/main/kotlin/LibsConfig.kt | 5 +++-- buildSrc/src/main/kotlin/PlatformConfig.kt | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/buildSrc/src/main/kotlin/LibsConfig.kt b/buildSrc/src/main/kotlin/LibsConfig.kt index 4fd69cb65..5d6e7892b 100644 --- a/buildSrc/src/main/kotlin/LibsConfig.kt +++ b/buildSrc/src/main/kotlin/LibsConfig.kt @@ -241,8 +241,9 @@ fun Project.applyLibrariesConfiguration() { scm { url.set("https://github.com/IntellectualSites/FastAsyncWorldEdit") - connection.set("scm:https://IntellectualSites@github.com/IntellectualSites/FastAsyncWorldEdit.git") - developerConnection.set("scm:git://github.com/IntellectualSites/FastAsyncWorldEdit.git") + connection.set("scm:git:https://github.com/IntellectualSites/FastAsyncWorldEdit.git") + developerConnection.set("scm:git:git@github.com:IntellectualSites/FastAsyncWorldEdit.git") + tag.set("${project.version}") } issueManagement { diff --git a/buildSrc/src/main/kotlin/PlatformConfig.kt b/buildSrc/src/main/kotlin/PlatformConfig.kt index 807ee9e8a..8f66ba55e 100644 --- a/buildSrc/src/main/kotlin/PlatformConfig.kt +++ b/buildSrc/src/main/kotlin/PlatformConfig.kt @@ -102,8 +102,9 @@ fun Project.applyPlatformAndCoreConfiguration() { scm { url.set("https://github.com/IntellectualSites/FastAsyncWorldEdit") - connection.set("scm:https://IntellectualSites@github.com/IntellectualSites/FastAsyncWorldEdit.git") - developerConnection.set("scm:git://github.com/IntellectualSites/FastAsyncWorldEdit.git") + connection.set("scm:git:https://github.com/IntellectualSites/FastAsyncWorldEdit.git") + developerConnection.set("scm:git:git@github.com:IntellectualSites/FastAsyncWorldEdit.git") + tag.set("${project.version}") } issueManagement{ From b9517a5cfb3fcf767ec60e0872bf0717ec6ced99 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Wed, 4 Oct 2023 13:46:24 +0200 Subject: [PATCH 030/466] [ci skip] Update publishing profile --- buildSrc/src/main/kotlin/PlatformConfig.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/buildSrc/src/main/kotlin/PlatformConfig.kt b/buildSrc/src/main/kotlin/PlatformConfig.kt index 8f66ba55e..8f737e9ce 100644 --- a/buildSrc/src/main/kotlin/PlatformConfig.kt +++ b/buildSrc/src/main/kotlin/PlatformConfig.kt @@ -87,16 +87,19 @@ fun Project.applyPlatformAndCoreConfiguration() { name.set("Alexander Brandes") email.set("contact(at)notmyfault.dev") organization.set("IntellectualSites") + organizationUrl.set("https://github.com/IntellectualSites") } developer { id.set("SirYwell") name.set("Hannes Greule") organization.set("IntellectualSites") + organizationUrl.set("https://github.com/IntellectualSites") } developer { id.set("dordsor21") name.set("dordsor21") organization.set("IntellectualSites") + organizationUrl.set("https://github.com/IntellectualSites") } } From 90d52f39d9f88fe6c027f91849a4230f7b3c5e8a Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 5 Oct 2023 14:54:52 +0100 Subject: [PATCH 031/466] fix: add null check for block targetted with inspect brush (#2443) --- .../core/command/tool/brush/InspectBrush.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/InspectBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/InspectBrush.java index 662212981..5ad9b818a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/InspectBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/InspectBrush.java @@ -74,7 +74,12 @@ public class InspectBrush extends BrushTool { return false; } try { - BlockVector3 target = getTarget(player, rightClick).toBlockPoint(); + Vector3 targetVector = getTarget(player, rightClick); + if (targetVector == null) { + player.print(Caption.of("worldedit.tool.no-block")); + return true; + } + BlockVector3 target = targetVector.toBlockPoint(); final int x = target.getBlockX(); final int y = target.getBlockY(); final int z = target.getBlockZ(); From aae92490144760dd8551bb62f374408bef7b6d35 Mon Sep 17 00:00:00 2001 From: opl- Date: Sat, 7 Oct 2023 20:16:21 +0200 Subject: [PATCH 032/466] Fix NullPointerException due to nullable source extent in ExtentEntityCopy (#2447) Fix NullPointerException due to nullable source extent Co-authored-by: opl <4833621+opl@users.noreply.github.com> --- .../sk89q/worldedit/function/entity/ExtentEntityCopy.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java index 7a034d7bd..fa3ef1dc4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java @@ -257,7 +257,8 @@ public class ExtentEntityCopy implements EntityFunction { //FAWE start if (hasRotation) { ListTag orgrot = state.getNbtData().getListTag("Rotation"); - Vector3 orgDirection = new Location(source, 0, 0, 0, orgrot.getFloat(0), orgrot.getFloat(1)).getDirection(); + // source extent may be null: use non-nullable destination instead since this is just a conversion into a vector. + Vector3 orgDirection = new Location(destination, 0, 0, 0, orgrot.getFloat(0), orgrot.getFloat(1)).getDirection(); Vector3 newDirection = transform.apply(orgDirection).subtract(transform.apply(Vector3.ZERO)).normalize(); builder.put( "Rotation", @@ -276,7 +277,8 @@ public class ExtentEntityCopy implements EntityFunction { CompoundTagBuilder builder = tag.createBuilder(); ListTag orgrot = state.getNbtData().getListTag("Rotation"); - Vector3 orgDirection = new Location(source, 0, 0, 0, orgrot.getFloat(0), orgrot.getFloat(1)).getDirection(); + // source extent may be null: use non-nullable destination instead since this is just a conversion into a vector. + Vector3 orgDirection = new Location(destination, 0, 0, 0, orgrot.getFloat(0), orgrot.getFloat(1)).getDirection(); Vector3 newDirection = transform.apply(orgDirection).subtract(transform.apply(Vector3.ZERO)).normalize(); builder.put( "Rotation", From f6865f6fee85130a2df1b9548c7cd7fc0a11c9ae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 17:45:51 +0200 Subject: [PATCH 033/466] Update dependency com.palmergames.bukkit.towny:towny to v0.99.6.0 (#2449) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 13066707a..f19eabc7e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "16.18.1" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.99.5.20" +towny = "0.99.6.0" plotsquared = "7.0.0" # Third party From bb52d2bdec71efa7a729c7f3d043c5f077ecd36f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 17:46:52 +0200 Subject: [PATCH 034/466] Update dependency gradle to v8.4 (#2450) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ac72c34e8..3fa8f862f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 0adc8e1a5..1aa94a426 100755 --- a/gradlew +++ b/gradlew @@ -145,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -153,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -202,11 +202,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ From 1de7f218c1c871dfb7e975fcb86121731d791df8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 17:47:06 +0200 Subject: [PATCH 035/466] Update dependency org.checkerframework:checker-qual to v3.39.0 (#2451) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f19eabc7e..b5bb1c241 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.14.0" adventure-bukkit = "4.3.1" -checkerqual = "3.38.0" +checkerqual = "3.39.0" truezip = "6.8.4" auto-value = "1.10.2" findbugs = "3.0.2" From 6bb2871b0be28855580cf0d75a10bd7bb9bd6d5f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 17:47:53 +0200 Subject: [PATCH 036/466] Update dependency org.mockito:mockito-core to v5.6.0 (#2452) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- worldedit-sponge/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b5bb1c241..d4617e857 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -46,7 +46,7 @@ text = "3.0.4" piston = "0.5.7" # Tests -mockito = "5.5.0" +mockito = "5.6.0" # Gradle plugins pluginyml = "0.6.0" diff --git a/worldedit-sponge/build.gradle.kts b/worldedit-sponge/build.gradle.kts index 3c6783886..f1aebbeba 100644 --- a/worldedit-sponge/build.gradle.kts +++ b/worldedit-sponge/build.gradle.kts @@ -28,7 +28,7 @@ dependencies { }) api("org.apache.logging.log4j:log4j-api") api("org.bstats:bstats-sponge:1.7") - testImplementation("org.mockito:mockito-core:5.5.0") + testImplementation("org.mockito:mockito-core:5.6.0") } <<<<<<< HEAD From 47cc61ea6f7ec7dc3f8f8d3a0aeb1ec340adbcb8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 17:49:25 +0200 Subject: [PATCH 037/466] Update auto.value to v1.10.4 (#2453) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d4617e857..1cd38a659 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -25,7 +25,7 @@ adventure = "4.14.0" adventure-bukkit = "4.3.1" checkerqual = "3.39.0" truezip = "6.8.4" -auto-value = "1.10.2" +auto-value = "1.10.4" findbugs = "3.0.2" rhino-runtime = "1.7.14" zstd-jni = "1.4.8-1" # Not latest as it can be difficult to obtain latest ZSTD libs From d0d97ce4cac7a69efb304efa4233643963c676a2 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Mon, 9 Oct 2023 17:58:28 +0200 Subject: [PATCH 038/466] Update paperweight --- worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts index 540d25cca..041ed296f 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ - the().paperDevBundle("1.20.2-R0.1-20230929.031919-14") + the().paperDevBundle("1.20.2-R0.1-20231008.101509-26") compileOnly(libs.paperlib) } From 639e956f23cf0b9deb337f0157a9696d9bd7dc37 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Mon, 9 Oct 2023 18:03:58 +0200 Subject: [PATCH 039/466] Release 2.8.1 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 44fa18649..57318af33 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s-%s", rootVersion, buildNumber) +version = String.format("%s", rootVersion) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From 186d24baed61a3078b486c41810c6c7bd1594a84 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Mon, 9 Oct 2023 18:25:24 +0200 Subject: [PATCH 040/466] Back to snapshot for development --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 57318af33..c79bb8083 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.8.1") +var rootVersion by extra("2.8.2") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s", rootVersion) +version = String.format("%s-%s", rootVersion, buildNumber) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From 470c75d843f3fb3251abc943d7a5be647c25ce8b Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sat, 14 Oct 2023 20:27:46 +0100 Subject: [PATCH 041/466] minor cleanup --- .../processor/heightmap/HeightmapProcessor.java | 4 +--- .../core/history/changeset/AbstractChangeSet.java | 12 ++++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightmapProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightmapProcessor.java index 3cdfeafb9..5d8f81e39 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightmapProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightmapProcessor.java @@ -12,8 +12,6 @@ import com.sk89q.worldedit.world.block.BlockTypesCache; import javax.annotation.Nullable; import java.util.Arrays; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; public class HeightmapProcessor implements IBatchProcessor { @@ -25,7 +23,7 @@ public class HeightmapProcessor implements IBatchProcessor { static { Arrays.fill(COMPLETE, true); - Arrays.fill(AIR_LAYER, (char) 1); + Arrays.fill(AIR_LAYER, (char) BlockTypesCache.ReservedIDs.AIR); } private final int minY; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java index b3493c896..c6a2d9bb0 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java @@ -179,14 +179,14 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { for (int z = 0; z < 16; z++) { int zz = z + bz; for (int x = 0; x < 16; x++, index++) { - int xx = bx + x; - int from = blocksGet[index]; - if (from == BlockTypesCache.ReservedIDs.__RESERVED__) { - from = BlockTypesCache.ReservedIDs.AIR; - } - final int combinedFrom = from; final int combinedTo = blocksSet[index]; if (combinedTo != BlockTypesCache.ReservedIDs.__RESERVED__) { + int xx = bx + x; + int from = blocksGet[index]; + if (from == BlockTypesCache.ReservedIDs.__RESERVED__) { + from = BlockTypesCache.ReservedIDs.AIR; + } + final int combinedFrom = from; add(xx, yy, zz, combinedFrom, combinedTo); } } From c6a9673b4b285f5adedfd2a861c0b67d9275b928 Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 18 Oct 2023 14:30:22 +0100 Subject: [PATCH 042/466] fix: avoid tripping async catcher when getting entity from chunk (#2464) --- .../impl/fawe/v1_20_R2/PaperweightGetBlocks.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java index d21510ff6..cbfd90ae2 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java @@ -295,7 +295,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public CompoundTag getEntity(UUID uuid) { - Entity entity = serverLevel.getEntity(uuid); + ensureLoaded(serverLevel, chunkX, chunkZ); + List entities = PaperweightPlatformAdapter.getEntities(getChunk()); + Entity entity = null; + for (Entity e : entities) { + if (e.getUUID().equals(uuid)) { + entity = e; + break; + } + } if (entity != null) { org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); From a6378606d67d1ba7547a02eb2bc14004e0605e52 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Wed, 18 Oct 2023 20:49:07 +0200 Subject: [PATCH 043/466] chore: update log4j2 javadoc url (#2466) update log4j2 javadoc url --- buildSrc/src/main/kotlin/CommonJavaConfig.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/CommonJavaConfig.kt b/buildSrc/src/main/kotlin/CommonJavaConfig.kt index 549a26037..99f854eef 100644 --- a/buildSrc/src/main/kotlin/CommonJavaConfig.kt +++ b/buildSrc/src/main/kotlin/CommonJavaConfig.kt @@ -59,7 +59,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean options.encoding = "UTF-8" links( "https://jd.advntr.dev/api/latest/", - "https://logging.apache.org/log4j/2.x/log4j-api/apidocs/", + "https://logging.apache.org/log4j/2.x/javadoc/log4j-api/", "https://www.antlr.org/api/Java/", "https://docs.enginehub.org/javadoc/org.enginehub.piston/core/0.5.7/", "https://docs.enginehub.org/javadoc/org.enginehub.piston/default-impl/0.5.7/", From 37161f9f69daf771b0a86e1fae6d4d69a8eaf7c7 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Wed, 18 Oct 2023 20:49:57 +0200 Subject: [PATCH 044/466] Remove dead javadoc URLs --- buildSrc/src/main/kotlin/CommonJavaConfig.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/buildSrc/src/main/kotlin/CommonJavaConfig.kt b/buildSrc/src/main/kotlin/CommonJavaConfig.kt index 99f854eef..8a111a2e7 100644 --- a/buildSrc/src/main/kotlin/CommonJavaConfig.kt +++ b/buildSrc/src/main/kotlin/CommonJavaConfig.kt @@ -61,8 +61,6 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean "https://jd.advntr.dev/api/latest/", "https://logging.apache.org/log4j/2.x/javadoc/log4j-api/", "https://www.antlr.org/api/Java/", - "https://docs.enginehub.org/javadoc/org.enginehub.piston/core/0.5.7/", - "https://docs.enginehub.org/javadoc/org.enginehub.piston/default-impl/0.5.7/", "https://jd.papermc.io/paper/1.20/", "https://intellectualsites.github.io/fastasyncworldedit-javadocs/worldedit-core/" ) From 50ecc5908d23cac0c7bca3082dbe00a6c18e9b74 Mon Sep 17 00:00:00 2001 From: Zeranny Date: Sat, 21 Oct 2023 16:27:39 +0100 Subject: [PATCH 045/466] Fix "cleared" ellipsoid/cylinder regions still passing isDefined check (#2465) --- .../worldedit/regions/selector/CylinderRegionSelector.java | 2 ++ .../worldedit/regions/selector/EllipsoidRegionSelector.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java index 689cd3701..0798b06e6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java @@ -254,6 +254,8 @@ public class CylinderRegionSelector implements RegionSelector, CUIRegion { @Override public void clear() { region = new CylinderRegion(region.getWorld()); + selectedCenter = false; + selectedRadius = false; } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/EllipsoidRegionSelector.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/EllipsoidRegionSelector.java index 02d570969..1f7c8a420 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/EllipsoidRegionSelector.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/EllipsoidRegionSelector.java @@ -227,6 +227,8 @@ public class EllipsoidRegionSelector implements RegionSelector, CUIRegion { public void clear() { region.setCenter(BlockVector3.ZERO); region.setRadius(Vector3.ZERO); + started = false; + selectedRadius = false; } @Override From 8c5bb96fdd39eb82d8288280fba2cdd1b7af3d0f Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sat, 21 Oct 2023 17:48:35 +0200 Subject: [PATCH 046/466] Streamline fawe thread names (#2467) streamline fawe thread names --- .../bukkit/adapter/Regenerator.java | 13 ++++++------- .../main/java/com/fastasyncworldedit/core/Fawe.java | 2 +- .../java/com/fastasyncworldedit/core/FaweCache.java | 4 ++-- .../util/task/FaweForkJoinWorkerThreadFactory.java | 5 ++++- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java index d0d9bb652..607bc75bf 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java @@ -41,6 +41,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.concurrent.ThreadFactory; import java.util.function.Function; /** @@ -158,16 +159,14 @@ public abstract class Regenerator(), - new ThreadFactoryBuilder().setNameFormat("fawe-clipboard-%d").build() + new ThreadFactoryBuilder().setNameFormat("FAWE Clipboard - %d").build() )); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java index af14624df..d8e1474e6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java @@ -18,6 +18,7 @@ import com.fastasyncworldedit.core.util.collection.CleanableThreadLocal; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.sk89q.jnbt.ByteArrayTag; import com.sk89q.jnbt.ByteTag; import com.sk89q.jnbt.CompoundTag; @@ -48,7 +49,6 @@ import java.util.Map.Entry; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -616,7 +616,7 @@ public enum FaweCache implements Trimable { ArrayBlockingQueue queue = new ArrayBlockingQueue<>(nThreads, true); return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, queue, - Executors.defaultThreadFactory(), + new ThreadFactoryBuilder().setNameFormat("FAWE Blocking Executor - %d").build(), new ThreadPoolExecutor.CallerRunsPolicy() ) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/task/FaweForkJoinWorkerThreadFactory.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/task/FaweForkJoinWorkerThreadFactory.java index 589b5b863..2c8353ce8 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/task/FaweForkJoinWorkerThreadFactory.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/task/FaweForkJoinWorkerThreadFactory.java @@ -2,19 +2,22 @@ package com.fastasyncworldedit.core.util.task; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinWorkerThread; +import java.util.concurrent.atomic.AtomicInteger; public class FaweForkJoinWorkerThreadFactory implements ForkJoinPool.ForkJoinWorkerThreadFactory { private final String nameFormat; + private final AtomicInteger idCounter; public FaweForkJoinWorkerThreadFactory(String nameFormat) { this.nameFormat = nameFormat; + this.idCounter = new AtomicInteger(0); } @Override public ForkJoinWorkerThread newThread(ForkJoinPool pool) { final ForkJoinWorkerThread worker = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool); - worker.setName(String.format(nameFormat, worker.getPoolIndex())); + worker.setName(String.format(nameFormat, idCounter.getAndIncrement())); return worker; } From 9489e5448f5efce2b20f03d82ae583f51d6eba9a Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 22 Oct 2023 08:01:44 +0100 Subject: [PATCH 047/466] fix: there is no need to synchronise chunk sending to the chunk GET instance (#2463) --- .../adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java | 7 +++++-- .../adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java | 7 +++++-- .../adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java | 7 +++++-- .../adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java | 7 +++++-- .../adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java | 7 +++++-- 5 files changed, 25 insertions(+), 10 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java index d7a1be074..7b01ccca1 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java @@ -98,6 +98,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private final int maxHeight; private final int minSectionPosition; private final int maxSectionPosition; + private final Object sendLock = new Object(); private LevelChunkSection[] sections; private LevelChunk levelChunk; private DataLayer[] blockLight; @@ -841,8 +842,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public synchronized void send(int mask, boolean lighting) { - PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); + public void send(int mask, boolean lighting) { + synchronized (sendLock) { + PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); + } } /** diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java index fba567a5b..0c76df36a 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java @@ -104,6 +104,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private final int maxSectionPosition; private final Registry biomeRegistry; private final IdMap> biomeHolderIdMap; + private final Object sendLock = new Object(); private LevelChunkSection[] sections; private LevelChunk levelChunk; private DataLayer[] blockLight; @@ -892,8 +893,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public synchronized void send(int mask, boolean lighting) { - PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); + public void send(int mask, boolean lighting) { + synchronized (sendLock) { + PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); + } } /** diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java index 0840b4aac..0171832aa 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java @@ -104,6 +104,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private final int maxSectionPosition; private final Registry biomeRegistry; private final IdMap> biomeHolderIdMap; + private final Object sendLock = new Object(); private LevelChunkSection[] sections; private LevelChunk levelChunk; private DataLayer[] blockLight; @@ -892,8 +893,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public synchronized void send(int mask, boolean lighting) { - PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); + public void send(int mask, boolean lighting) { + synchronized (sendLock) { + PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); + } } /** diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java index e0e746109..e983a8e70 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java @@ -104,6 +104,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private final int maxSectionPosition; private final Registry biomeRegistry; private final IdMap> biomeHolderIdMap; + private final Object sendLock = new Object(); private LevelChunkSection[] sections; private LevelChunk levelChunk; private DataLayer[] blockLight; @@ -890,8 +891,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public synchronized void send(int mask, boolean lighting) { - PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); + public void send(int mask, boolean lighting) { + synchronized (sendLock) { + PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); + } } /** diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java index cbfd90ae2..c8ae9c80f 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java @@ -83,6 +83,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private final int maxSectionPosition; private final Registry biomeRegistry; private final IdMap> biomeHolderIdMap; + private final Object sendLock = new Object(); private LevelChunkSection[] sections; private LevelChunk levelChunk; private DataLayer[] blockLight; @@ -877,8 +878,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public synchronized void send(int mask, boolean lighting) { - PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); + public void send(int mask, boolean lighting) { + synchronized (sendLock) { + PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); + } } /** From f5803a09f6f4c1b3252d2701e69ef274daf97b0f Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 22 Oct 2023 11:04:19 +0100 Subject: [PATCH 048/466] fix: vastly superier handling of queue chunks (#2461) - remove ChunkHolder locking concept as this is no longer needed - previously we obtained the copy from chunk GET on finalize, meaning the copy could be replaced by a "newer" one (bad) - work around this issue by introducing concept of "unique" keys to map chunk GET copies to - correctly handle resetting of various chunk-related classes to actually allow pooling to work - remove chunks as they are submitted when flushing a SingleThreadQueueExtenting --- .../fawe/v1_17_R1_2/PaperweightGetBlocks.java | 43 +++++-- .../v1_17_R1_2/PaperweightGetBlocks_Copy.java | 8 +- .../fawe/v1_18_R2/PaperweightGetBlocks.java | 46 +++++-- .../v1_18_R2/PaperweightGetBlocks_Copy.java | 9 +- .../fawe/v1_19_R3/PaperweightGetBlocks.java | 43 +++++-- .../v1_19_R3/PaperweightGetBlocks_Copy.java | 8 +- .../fawe/v1_20_R1/PaperweightGetBlocks.java | 43 +++++-- .../v1_20_R1/PaperweightGetBlocks_Copy.java | 8 +- .../fawe/v1_20_R2/PaperweightGetBlocks.java | 43 +++++-- .../v1_20_R2/PaperweightGetBlocks_Copy.java | 8 +- .../core/queue/IChunkGet.java | 22 +++- .../core/queue/IQueueChunk.java | 14 +++ .../SingleThreadQueueExtent.java | 12 +- .../implementation/blocks/CharBlocks.java | 1 + .../implementation/blocks/NullChunkGet.java | 3 +- .../implementation/chunk/ChunkHolder.java | 113 +++++------------- .../queue/implementation/chunk/NullChunk.java | 3 +- 17 files changed, 275 insertions(+), 152 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java index 7b01ccca1..a93437c1a 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java @@ -72,9 +72,11 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Function; import java.util.stream.Collectors; @@ -91,6 +93,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc .getInstance() .getBukkitImplAdapter()); private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); + private final ReentrantLock callLock = new ReentrantLock(); private final ServerLevel serverLevel; private final int chunkX; private final int chunkZ; @@ -98,15 +101,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private final int maxHeight; private final int minSectionPosition; private final int maxSectionPosition; + private final ConcurrentHashMap copies = new ConcurrentHashMap<>(); private final Object sendLock = new Object(); private LevelChunkSection[] sections; private LevelChunk levelChunk; private DataLayer[] blockLight; private DataLayer[] skyLight; private boolean createCopy = false; - private PaperweightGetBlocks_Copy copy = null; private boolean forceLoadSections = true; private boolean lightUpdate = false; + private int copyKey = 0; public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { this(((CraftWorld) world).getHandle(), chunkX, chunkZ); @@ -139,13 +143,27 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public void setCreateCopy(boolean createCopy) { + public int setCreateCopy(boolean createCopy) { + if (!callLock.isHeldByCurrentThread()) { + throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); + } this.createCopy = createCopy; + return ++this.copyKey; } @Override - public IChunkGet getCopy() { - return copy; + public IChunkGet getCopy(final int key) { + return copies.remove(key); + } + + @Override + public void lockCall() { + this.callLock.lock(); + } + + @Override + public void unlockCall() { + this.callLock.unlock(); } @Override @@ -394,8 +412,17 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override @SuppressWarnings("rawtypes") public synchronized > T call(IChunkSet set, Runnable finalizer) { + if (!callLock.isHeldByCurrentThread()) { + throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked."); + } forceLoadSections = false; - copy = createCopy ? new PaperweightGetBlocks_Copy(getChunk()) : null; + PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + if (createCopy) { + if (copies.containsKey(copyKey)) { + throw new IllegalStateException("Copy key already used."); + } + copies.put(copyKey, copy); + } try { ServerLevel nmsWorld = serverLevel; LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); @@ -832,9 +859,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (super.sections[layer] != null) { synchronized (super.sectionLocks[layer]) { if (super.sections[layer].isFull() && super.blocks[layer] != null) { - char[] blocks = new char[4096]; - System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096); - return blocks; + return super.blocks[layer]; } } } @@ -949,9 +974,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc public LevelChunkSection[] getSections(boolean force) { force &= forceLoadSections; - sectionLock.readLock().lock(); LevelChunkSection[] tmp = sections; - sectionLock.readLock().unlock(); if (tmp == null || force) { try { sectionLock.writeLock().lock(); diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java index 65b16ee3b..cd9987d79 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java @@ -22,6 +22,7 @@ import net.minecraft.world.level.chunk.ChunkBiomeContainer; import net.minecraft.world.level.chunk.LevelChunk; import javax.annotation.Nullable; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -99,7 +100,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { } @Override - public void setCreateCopy(boolean createCopy) { + public int setCreateCopy(boolean createCopy) { + return -1; } @Override @@ -196,6 +198,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { @Override public char[] load(int layer) { layer -= getMinSectionPosition(); + if (blocks[layer] == null) { + blocks[layer] = new char[4096]; + Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR); + } return blocks[layer]; } diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java index 0c76df36a..81580910c 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java @@ -14,7 +14,6 @@ import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.collection.AdaptedMap; import com.google.common.base.Suppliers; -import com.google.common.collect.Iterables; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.StringTag; @@ -66,7 +65,6 @@ import javax.annotation.Nonnull; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -76,13 +74,14 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Function; import java.util.stream.Collectors; -import java.util.stream.StreamSupport; public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks { @@ -95,6 +94,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc .getInstance() .getBukkitImplAdapter()); private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); + private final ReentrantLock callLock = new ReentrantLock(); private final ServerLevel serverLevel; private final int chunkX; private final int chunkZ; @@ -104,15 +104,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private final int maxSectionPosition; private final Registry biomeRegistry; private final IdMap> biomeHolderIdMap; + private final ConcurrentHashMap copies = new ConcurrentHashMap<>(); private final Object sendLock = new Object(); private LevelChunkSection[] sections; private LevelChunk levelChunk; private DataLayer[] blockLight; private DataLayer[] skyLight; private boolean createCopy = false; - private PaperweightGetBlocks_Copy copy = null; private boolean forceLoadSections = true; private boolean lightUpdate = false; + private int copyKey = 0; public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { this(((CraftWorld) world).getHandle(), chunkX, chunkZ); @@ -147,13 +148,27 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public void setCreateCopy(boolean createCopy) { + public int setCreateCopy(boolean createCopy) { + if (!callLock.isHeldByCurrentThread()) { + throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); + } this.createCopy = createCopy; + return ++this.copyKey; } @Override - public IChunkGet getCopy() { - return copy; + public IChunkGet getCopy(final int key) { + return copies.remove(key); + } + + @Override + public void lockCall() { + this.callLock.lock(); + } + + @Override + public void unlockCall() { + this.callLock.unlock(); } @Override @@ -388,8 +403,17 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override @SuppressWarnings("rawtypes") public synchronized > T call(IChunkSet set, Runnable finalizer) { + if (!callLock.isHeldByCurrentThread()) { + throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked."); + } forceLoadSections = false; - copy = createCopy ? new PaperweightGetBlocks_Copy(getChunk()) : null; + PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + if (createCopy) { + if (copies.containsKey(copyKey)) { + throw new IllegalStateException("Copy key already used."); + } + copies.put(copyKey, copy); + } try { ServerLevel nmsWorld = serverLevel; LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); @@ -883,9 +907,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (super.sections[layer] != null) { synchronized (super.sectionLocks[layer]) { if (super.sections[layer].isFull() && super.blocks[layer] != null) { - char[] blocks = new char[4096]; - System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096); - return blocks; + return super.blocks[layer]; } } } @@ -1007,9 +1029,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc public LevelChunkSection[] getSections(boolean force) { force &= forceLoadSections; - sectionLock.readLock().lock(); LevelChunkSection[] tmp = sections; - sectionLock.readLock().unlock(); if (tmp == null || force) { try { sectionLock.writeLock().lock(); diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks_Copy.java index 5c68de6fe..b007ea3b4 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks_Copy.java @@ -11,7 +11,6 @@ import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypesCache; @@ -24,6 +23,7 @@ import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.PalettedContainer; import javax.annotation.Nullable; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -101,7 +101,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { } @Override - public void setCreateCopy(boolean createCopy) { + public int setCreateCopy(boolean createCopy) { + return -1; } @Override @@ -187,6 +188,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { @Override public char[] load(int layer) { layer -= getMinSectionPosition(); + if (blocks[layer] == null) { + blocks[layer] = new char[4096]; + Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR); + } return blocks[layer]; } diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java index 0171832aa..60695c1e8 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java @@ -75,9 +75,11 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Function; import java.util.stream.Collectors; @@ -95,6 +97,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc .getInstance() .getBukkitImplAdapter()); private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); + private final ReentrantLock callLock = new ReentrantLock(); private final ServerLevel serverLevel; private final int chunkX; private final int chunkZ; @@ -104,15 +107,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private final int maxSectionPosition; private final Registry biomeRegistry; private final IdMap> biomeHolderIdMap; + private final ConcurrentHashMap copies = new ConcurrentHashMap<>(); private final Object sendLock = new Object(); private LevelChunkSection[] sections; private LevelChunk levelChunk; private DataLayer[] blockLight; private DataLayer[] skyLight; private boolean createCopy = false; - private PaperweightGetBlocks_Copy copy = null; private boolean forceLoadSections = true; private boolean lightUpdate = false; + private int copyKey = 0; public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { this(((CraftWorld) world).getHandle(), chunkX, chunkZ); @@ -147,13 +151,27 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public void setCreateCopy(boolean createCopy) { + public int setCreateCopy(boolean createCopy) { + if (!callLock.isHeldByCurrentThread()) { + throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); + } this.createCopy = createCopy; + return ++this.copyKey; } @Override - public IChunkGet getCopy() { - return copy; + public IChunkGet getCopy(final int key) { + return copies.remove(key); + } + + @Override + public void lockCall() { + this.callLock.lock(); + } + + @Override + public void unlockCall() { + this.callLock.unlock(); } @Override @@ -389,8 +407,17 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override @SuppressWarnings("rawtypes") public synchronized > T call(IChunkSet set, Runnable finalizer) { + if (!callLock.isHeldByCurrentThread()) { + throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked."); + } forceLoadSections = false; - copy = createCopy ? new PaperweightGetBlocks_Copy(getChunk()) : null; + PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + if (createCopy) { + if (copies.containsKey(copyKey)) { + throw new IllegalStateException("Copy key already used."); + } + copies.put(copyKey, copy); + } try { ServerLevel nmsWorld = serverLevel; LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); @@ -883,9 +910,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (super.sections[layer] != null) { synchronized (super.sectionLocks[layer]) { if (super.sections[layer].isFull() && super.blocks[layer] != null) { - char[] blocks = new char[4096]; - System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096); - return blocks; + return super.blocks[layer]; } } } @@ -1007,9 +1032,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc public LevelChunkSection[] getSections(boolean force) { force &= forceLoadSections; - sectionLock.readLock().lock(); LevelChunkSection[] tmp = sections; - sectionLock.readLock().unlock(); if (tmp == null || force) { try { sectionLock.writeLock().lock(); diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java index 0c5d62692..7e908c74c 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java @@ -26,6 +26,7 @@ import net.minecraft.world.level.chunk.PalettedContainerRO; import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -105,7 +106,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { } @Override - public void setCreateCopy(boolean createCopy) { + public int setCreateCopy(boolean createCopy) { + return -1; } @Override @@ -199,6 +201,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { @Override public char[] load(int layer) { layer -= getMinSectionPosition(); + if (blocks[layer] == null) { + blocks[layer] = new char[4096]; + Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR); + } return blocks[layer]; } diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java index e983a8e70..67bcd6902 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java @@ -75,9 +75,11 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Function; import java.util.stream.Collectors; @@ -95,6 +97,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc .getInstance() .getBukkitImplAdapter()); private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); + private final ReentrantLock callLock = new ReentrantLock(); private final ServerLevel serverLevel; private final int chunkX; private final int chunkZ; @@ -104,15 +107,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private final int maxSectionPosition; private final Registry biomeRegistry; private final IdMap> biomeHolderIdMap; + private final ConcurrentHashMap copies = new ConcurrentHashMap<>(); private final Object sendLock = new Object(); private LevelChunkSection[] sections; private LevelChunk levelChunk; private DataLayer[] blockLight; private DataLayer[] skyLight; private boolean createCopy = false; - private PaperweightGetBlocks_Copy copy = null; private boolean forceLoadSections = true; private boolean lightUpdate = false; + private int copyKey = 0; public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { this(((CraftWorld) world).getHandle(), chunkX, chunkZ); @@ -147,13 +151,27 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public void setCreateCopy(boolean createCopy) { + public int setCreateCopy(boolean createCopy) { + if (!callLock.isHeldByCurrentThread()) { + throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); + } this.createCopy = createCopy; + return ++this.copyKey; } @Override - public IChunkGet getCopy() { - return copy; + public IChunkGet getCopy(final int key) { + return copies.remove(key); + } + + @Override + public void lockCall() { + this.callLock.lock(); + } + + @Override + public void unlockCall() { + this.callLock.unlock(); } @Override @@ -388,8 +406,17 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override @SuppressWarnings("rawtypes") public synchronized > T call(IChunkSet set, Runnable finalizer) { + if (!callLock.isHeldByCurrentThread()) { + throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked."); + } forceLoadSections = false; - copy = createCopy ? new PaperweightGetBlocks_Copy(getChunk()) : null; + PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + if (createCopy) { + if (copies.containsKey(copyKey)) { + throw new IllegalStateException("Copy key already used."); + } + copies.put(copyKey, copy); + } try { ServerLevel nmsWorld = serverLevel; LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); @@ -881,9 +908,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (super.sections[layer] != null) { synchronized (super.sectionLocks[layer]) { if (super.sections[layer].isFull() && super.blocks[layer] != null) { - char[] blocks = new char[4096]; - System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096); - return blocks; + return super.blocks[layer]; } } } @@ -1005,9 +1030,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc public LevelChunkSection[] getSections(boolean force) { force &= forceLoadSections; - sectionLock.readLock().lock(); LevelChunkSection[] tmp = sections; - sectionLock.readLock().unlock(); if (tmp == null || force) { try { sectionLock.writeLock().lock(); diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java index a23000249..a3ca91376 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java @@ -26,6 +26,7 @@ import net.minecraft.world.level.chunk.PalettedContainerRO; import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -105,7 +106,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { } @Override - public void setCreateCopy(boolean createCopy) { + public int setCreateCopy(boolean createCopy) { + return -1; } @Override @@ -199,6 +201,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { @Override public char[] load(int layer) { layer -= getMinSectionPosition(); + if (blocks[layer] == null) { + blocks[layer] = new char[4096]; + Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR); + } return blocks[layer]; } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java index c8ae9c80f..d51d31500 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java @@ -54,9 +54,11 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import javax.annotation.Nonnull; import java.util.*; import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Function; import java.util.stream.Collectors; @@ -74,6 +76,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc .getInstance() .getBukkitImplAdapter()); private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); + private final ReentrantLock callLock = new ReentrantLock(); private final ServerLevel serverLevel; private final int chunkX; private final int chunkZ; @@ -83,15 +86,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private final int maxSectionPosition; private final Registry biomeRegistry; private final IdMap> biomeHolderIdMap; + private final ConcurrentHashMap copies = new ConcurrentHashMap<>(); private final Object sendLock = new Object(); private LevelChunkSection[] sections; private LevelChunk levelChunk; private DataLayer[] blockLight; private DataLayer[] skyLight; private boolean createCopy = false; - private PaperweightGetBlocks_Copy copy = null; private boolean forceLoadSections = true; private boolean lightUpdate = false; + private int copyKey = 0; public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { this(((CraftWorld) world).getHandle(), chunkX, chunkZ); @@ -126,13 +130,27 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public void setCreateCopy(boolean createCopy) { + public int setCreateCopy(boolean createCopy) { + if (!callLock.isHeldByCurrentThread()) { + throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); + } this.createCopy = createCopy; + return ++this.copyKey; } @Override - public IChunkGet getCopy() { - return copy; + public IChunkGet getCopy(final int key) { + return copies.remove(key); + } + + @Override + public void lockCall() { + this.callLock.lock(); + } + + @Override + public void unlockCall() { + this.callLock.unlock(); } @Override @@ -375,8 +393,17 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override @SuppressWarnings("rawtypes") public synchronized > T call(IChunkSet set, Runnable finalizer) { + if (!callLock.isHeldByCurrentThread()) { + throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked."); + } forceLoadSections = false; - copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + if (createCopy) { + if (copies.containsKey(copyKey)) { + throw new IllegalStateException("Copy key already used."); + } + copies.put(copyKey, copy); + } try { ServerLevel nmsWorld = serverLevel; LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); @@ -868,9 +895,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (super.sections[layer] != null) { synchronized (super.sectionLocks[layer]) { if (super.sections[layer].isFull() && super.blocks[layer] != null) { - char[] blocks = new char[4096]; - System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096); - return blocks; + return super.blocks[layer]; } } } @@ -992,9 +1017,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc public LevelChunkSection[] getSections(boolean force) { force &= forceLoadSections; - sectionLock.readLock().lock(); LevelChunkSection[] tmp = sections; - sectionLock.readLock().unlock(); if (tmp == null || force) { try { sectionLock.writeLock().lock(); diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java index 428161a48..1c1130764 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java @@ -26,6 +26,7 @@ import net.minecraft.world.level.chunk.PalettedContainerRO; import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -105,7 +106,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { } @Override - public void setCreateCopy(boolean createCopy) { + public int setCreateCopy(boolean createCopy) { + return -1; } @Override @@ -199,6 +201,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { @Override public char[] load(int layer) { layer -= getMinSectionPosition(); + if (blocks[layer] == null) { + blocks[layer] = new char[4096]; + Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR); + } return blocks[layer]; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java index 8004f7098..a3fc6b78a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java @@ -50,13 +50,31 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent, ITileInput { boolean isCreateCopy(); - void setCreateCopy(boolean createCopy); + /** + * Not for external API use. Internal use only. + */ + int setCreateCopy(boolean createCopy); @Nullable - default IChunkGet getCopy() { + default IChunkGet getCopy(int key) { return null; } + /** + * Lock the {@link IChunkGet#call(IChunkSet, Runnable)} method to the current thread using a reentrant lock. Also locks + * related methods e.g. {@link IChunkGet#setCreateCopy(boolean)} + * + * @since TODO + */ + default void lockCall() {} + + /** + * Unlock {@link IChunkGet#call(IChunkSet, Runnable)} (and other related methods) to executions from other threads + * + * @since TODO + */ + default void unlockCall() {} + /** * Flush the block lighting array (section*blocks) to the chunk GET between the given section indices. Negative allowed. * diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueChunk.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueChunk.java index 72732378d..9dda1d006 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueChunk.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueChunk.java @@ -36,4 +36,18 @@ public interface IQueueChunk> extends IChunk, Callable { } } + /** + * Get if the thank has any running tasks, locked locks, etc. + */ + default boolean hasRunning() { + return false; + } + + /** + * Prevent set operations to the chunk, should typically be used when a chunk is submitted before the edit is necessarily + * completed. + */ + default void lockSet() { + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java index 198782ee3..34dd5191e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java @@ -62,8 +62,8 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen private boolean initialized; private Thread currentThread; // Last access pointers - private IQueueChunk lastChunk; - private long lastPair = Long.MAX_VALUE; + private volatile IQueueChunk lastChunk; + private volatile long lastPair = Long.MAX_VALUE; private boolean enabledQueue = true; private boolean fastmode = false; // Array for lazy avoidance of concurrent modification exceptions and needless overcomplication of code (synchronisation is @@ -283,6 +283,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen private ChunkHolder poolOrCreate(int chunkX, int chunkZ) { ChunkHolder next = create(false); next.init(this, chunkX, chunkZ); + next.setFastMode(isFastMode()); return next; } @@ -454,7 +455,8 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen if (!chunks.isEmpty()) { getChunkLock.lock(); if (MemUtil.isMemoryLimited()) { - for (IQueueChunk chunk : chunks.values()) { + while (!chunks.isEmpty()) { + IQueueChunk chunk = chunks.removeFirst(); final Future future = submitUnchecked(chunk); if (future != null && !future.isDone()) { pollSubmissions(Settings.settings().QUEUE.PARALLEL_THREADS, true); @@ -462,14 +464,14 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen } } } else { - for (IQueueChunk chunk : chunks.values()) { + while (!chunks.isEmpty()) { + IQueueChunk chunk = chunks.removeFirst(); final Future future = submitUnchecked(chunk); if (future != null && !future.isDone()) { submissions.add(future); } } } - chunks.clear(); getChunkLock.unlock(); } pollSubmissions(0, true); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java index 85cadd9ef..6eae2db5b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java @@ -121,6 +121,7 @@ public abstract class CharBlocks implements IBlocks { public synchronized IChunkSet reset() { for (int i = 0; i < sectionCount; i++) { sections[i] = EMPTY; + blocks[i] = null; } return null; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/NullChunkGet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/NullChunkGet.java index 8f7b8007c..042870666 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/NullChunkGet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/NullChunkGet.java @@ -69,7 +69,8 @@ public final class NullChunkGet implements IChunkGet { } @Override - public void setCreateCopy(boolean createCopy) { + public int setCreateCopy(boolean createCopy) { + return -1; } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java index ec556d845..e4a18ef69 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java @@ -25,8 +25,6 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.Future; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; /** * An abstract {@link IChunk} class that implements basic get/set blocks. @@ -44,8 +42,6 @@ public class ChunkHolder> implements IQueueChunk { return POOL.poll(); } - private final Lock calledLock = new ReentrantLock(); - private volatile IChunkGet chunkExisting; // The existing chunk (e.g. a clipboard, or the world, before changes) private volatile IChunkSet chunkSet; // The blocks to be set to the chunkExisting private IBlockDelegate delegate; // delegate handles the abstraction of the chunk layers @@ -68,7 +64,6 @@ public class ChunkHolder> implements IQueueChunk { @Override public synchronized void recycle() { - calledLock.lock(); delegate = NULL; if (chunkSet != null) { chunkSet.recycle(); @@ -77,7 +72,6 @@ public class ChunkHolder> implements IQueueChunk { chunkExisting = null; extent = null; POOL.offer(this); - calledLock.unlock(); } public long initAge() { @@ -88,68 +82,49 @@ public class ChunkHolder> implements IQueueChunk { return delegate; } - /** - * If the chunk is currently being "called", this method will block until completed. - */ - private void checkAndWaitOnCalledLock() { - if (!calledLock.tryLock()) { - calledLock.lock(); - } - calledLock.unlock(); - } - @Override public boolean setTile(int x, int y, int z, CompoundTag tag) { - checkAndWaitOnCalledLock(); return delegate.set(this).setTile(x, y, z, tag); } @Override public CompoundTag getTile(int x, int y, int z) { - checkAndWaitOnCalledLock(); return delegate.set(this).getTile(x, y, z); } @Override public void setEntity(CompoundTag tag) { - checkAndWaitOnCalledLock(); delegate.set(this).setEntity(tag); } @Override public void removeEntity(UUID uuid) { - checkAndWaitOnCalledLock(); delegate.set(this).removeEntity(uuid); } @Override public Set getEntityRemoves() { - checkAndWaitOnCalledLock(); return delegate.set(this).getEntityRemoves(); } @Override public BiomeType[][] getBiomes() { - checkAndWaitOnCalledLock(); // Uses set as this method is only used to retrieve biomes that have been set to the extent/chunk. return delegate.set(this).getBiomes(); } @Override public char[][] getLight() { - checkAndWaitOnCalledLock(); return delegate.set(this).getLight(); } @Override public char[][] getSkyLight() { - checkAndWaitOnCalledLock(); return delegate.set(this).getSkyLight(); } @Override public void setBlocks(int layer, char[] data) { - checkAndWaitOnCalledLock(); delegate.set(this).setBlocks(layer, data); } @@ -174,12 +149,10 @@ public class ChunkHolder> implements IQueueChunk { @Override public void setFastMode(boolean fastmode) { - checkAndWaitOnCalledLock(); this.fastmode = fastmode; } public void setBitMask(int bitMask) { - checkAndWaitOnCalledLock(); this.bitMask = bitMask; } @@ -189,7 +162,6 @@ public class ChunkHolder> implements IQueueChunk { @Override public boolean hasBiomes(final int layer) { - checkAndWaitOnCalledLock(); // No need to go through delegate. hasBiomes is SET only. return chunkSet != null && chunkSet.hasBiomes(layer); } @@ -200,14 +172,13 @@ public class ChunkHolder> implements IQueueChunk { @Override public CompoundTag getEntity(UUID uuid) { - checkAndWaitOnCalledLock(); return delegate.get(this).getEntity(uuid); } @Override - public void setCreateCopy(boolean createCopy) { - checkAndWaitOnCalledLock(); + public int setCreateCopy(boolean createCopy) { this.createCopy = createCopy; + return -1; } @Override @@ -217,19 +188,16 @@ public class ChunkHolder> implements IQueueChunk { @Override public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { - checkAndWaitOnCalledLock(); delegate.setLightingToGet(this, lighting); } @Override public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { - checkAndWaitOnCalledLock(); delegate.setSkyLightingToGet(this, lighting); } @Override public void setHeightmapToGet(HeightMapType type, int[] data) { - checkAndWaitOnCalledLock(); delegate.setHeightmapToGet(this, type, data); } @@ -254,7 +222,6 @@ public class ChunkHolder> implements IQueueChunk { } public void flushLightToGet() { - checkAndWaitOnCalledLock(); delegate.flushLightToGet(this); } @@ -921,19 +888,16 @@ public class ChunkHolder> implements IQueueChunk { @Override public Map getTiles() { - checkAndWaitOnCalledLock(); return delegate.get(this).getTiles(); } @Override public Set getEntities() { - checkAndWaitOnCalledLock(); return delegate.get(this).getEntities(); } @Override public boolean hasSection(int layer) { - checkAndWaitOnCalledLock(); return chunkExisting != null && chunkExisting.hasSection(layer); } @@ -958,6 +922,7 @@ public class ChunkHolder> implements IQueueChunk { if (result) { delegate = NULL; chunkExisting = null; + chunkSet.recycle(); chunkSet = null; return true; } @@ -985,7 +950,6 @@ public class ChunkHolder> implements IQueueChunk { @Override public boolean isEmpty() { - checkAndWaitOnCalledLock(); return chunkSet == null || chunkSet.isEmpty(); } @@ -993,7 +957,6 @@ public class ChunkHolder> implements IQueueChunk { * Get or create the existing part of this chunk. */ public final IChunkGet getOrCreateGet() { - checkAndWaitOnCalledLock(); if (chunkExisting == null) { chunkExisting = newWrappedGet(); chunkExisting.trim(false); @@ -1005,7 +968,6 @@ public class ChunkHolder> implements IQueueChunk { * Get or create the settable part of this chunk. */ public final IChunkSet getOrCreateSet() { - checkAndWaitOnCalledLock(); if (chunkSet == null) { chunkSet = newWrappedSet(); } @@ -1026,7 +988,7 @@ public class ChunkHolder> implements IQueueChunk { * - The purpose of wrapping is to allow different extents to intercept / alter behavior * - e.g., caching, optimizations, filtering */ - private synchronized IChunkGet newWrappedGet() { + private IChunkGet newWrappedGet() { return extent.getCachedGet(chunkX, chunkZ); } @@ -1048,42 +1010,42 @@ public class ChunkHolder> implements IQueueChunk { @Override public synchronized T call() { - calledLock.lock(); if (chunkSet != null && !chunkSet.isEmpty()) { - this.delegate = GET; chunkSet.setBitMask(bitMask); - try { - IChunkSet copy = chunkSet.createCopy(); - chunkSet = null; - return this.call(copy, () -> { - // Do nothing - }); - } catch (Throwable t) { - calledLock.unlock(); - throw t; - } + IChunkSet copy = chunkSet.createCopy(); + return this.call(copy, () -> { + // Do nothing + }); } + recycle(); return null; } + /** + * This method should never be called from outside ChunkHolder + */ @Override public synchronized T call(IChunkSet set, Runnable finalize) { if (set != null) { IChunkGet get = getOrCreateGet(); - boolean postProcess = !(getExtent().getPostProcessor() instanceof EmptyBatchProcessor); - get.setCreateCopy(postProcess); - final IChunkSet iChunkSet = getExtent().processSet(this, get, set); - Runnable finalizer; - if (postProcess) { - finalizer = () -> { - getExtent().postProcess(this, get.getCopy(), iChunkSet); - finalize.run(); - }; - } else { - finalizer = finalize; + try { + get.lockCall(); + boolean postProcess = !(getExtent().getPostProcessor() instanceof EmptyBatchProcessor); + final IChunkSet iChunkSet = getExtent().processSet(this, get, set); + Runnable finalizer; + if (postProcess) { + int copyKey = get.setCreateCopy(true); + finalizer = () -> { + getExtent().postProcess(this, get.getCopy(copyKey), iChunkSet); + finalize.run(); + }; + } else { + finalizer = finalize; + } + return get.call(set, finalizer); + } finally { + get.unlockCall(); } - calledLock.unlock(); - return get.call(set, finalizer); } return null; } @@ -1107,103 +1069,86 @@ public class ChunkHolder> implements IQueueChunk { @Override public boolean setBiome(int x, int y, int z, BiomeType biome) { - checkAndWaitOnCalledLock(); return delegate.setBiome(this, x, y, z, biome); } @Override public > boolean setBlock(int x, int y, int z, B block) { - checkAndWaitOnCalledLock(); return delegate.setBlock(this, x, y, z, block); } @Override public BiomeType getBiomeType(int x, int y, int z) { - checkAndWaitOnCalledLock(); return delegate.getBiome(this, x, y, z); } @Override public BlockState getBlock(int x, int y, int z) { - checkAndWaitOnCalledLock(); return delegate.getBlock(this, x, y, z); } @Override public BaseBlock getFullBlock(int x, int y, int z) { - checkAndWaitOnCalledLock(); return delegate.getFullBlock(this, x, y, z); } @Override public void setSkyLight(int x, int y, int z, int value) { - checkAndWaitOnCalledLock(); delegate.setSkyLight(this, x, y, z, value); } @Override public void setHeightMap(HeightMapType type, int[] heightMap) { - checkAndWaitOnCalledLock(); delegate.setHeightMap(this, type, heightMap); } @Override public void removeSectionLighting(int layer, boolean sky) { - checkAndWaitOnCalledLock(); delegate.removeSectionLighting(this, layer, sky); } @Override public void setFullBright(int layer) { - checkAndWaitOnCalledLock(); delegate.setFullBright(this, layer); } @Override public void setBlockLight(int x, int y, int z, int value) { - checkAndWaitOnCalledLock(); delegate.setBlockLight(this, x, y, z, value); } @Override public void setLightLayer(int layer, char[] toSet) { - checkAndWaitOnCalledLock(); delegate.setLightLayer(this, layer, toSet); } @Override public void setSkyLightLayer(int layer, char[] toSet) { - checkAndWaitOnCalledLock(); delegate.setSkyLightLayer(this, layer, toSet); } @Override public int getSkyLight(int x, int y, int z) { - checkAndWaitOnCalledLock(); return delegate.getSkyLight(this, x, y, z); } @Override public int getEmittedLight(int x, int y, int z) { - checkAndWaitOnCalledLock(); return delegate.getEmittedLight(this, x, y, z); } @Override public int getBrightness(int x, int y, int z) { - checkAndWaitOnCalledLock(); return delegate.getBrightness(this, x, y, z); } @Override public int getOpacity(int x, int y, int z) { - checkAndWaitOnCalledLock(); return delegate.getOpacity(this, x, y, z); } @Override public int[] getHeightMap(HeightMapType type) { - checkAndWaitOnCalledLock(); return delegate.getHeightMap(this, type); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java index 99757a513..8cc6471ba 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java @@ -184,7 +184,8 @@ public final class NullChunk implements IQueueChunk { } @Override - public void setCreateCopy(boolean createCopy) { + public int setCreateCopy(boolean createCopy) { + return -1; } @Override From 6bb8a2cd3c53b3ba3041b16abd4589f8ff4b9d58 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 22 Oct 2023 12:51:11 +0200 Subject: [PATCH 049/466] Label PRs with merge conflicts (#2468) --- .github/workflows/label-merge-conflicts.yaml | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/label-merge-conflicts.yaml diff --git a/.github/workflows/label-merge-conflicts.yaml b/.github/workflows/label-merge-conflicts.yaml new file mode 100644 index 000000000..d189f5520 --- /dev/null +++ b/.github/workflows/label-merge-conflicts.yaml @@ -0,0 +1,23 @@ +name: "Label conflicting PRs" +on: + push: + pull_request_target: + types: [ synchronize ] + pull_request: + types: [ synchronize ] + +permissions: + pull-requests: write + +jobs: + main: + if: github.event.pull_request.user.login != 'dependabot[bot]' + runs-on: ubuntu-latest + steps: + - name: Label conflicting PRs + uses: eps1lon/actions-label-merge-conflict@v2.1.0 + with: + dirtyLabel: "unresolved-merge-conflict" + repoToken: "${{ secrets.GITHUB_TOKEN }}" + commentOnDirty: "Please take a moment and address the merge conflicts of your pull request. Thanks!" + continueOnMissingPermissions: true From 6dfa7d17329d6dcf8970e6fff33116b1c5218091 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sun, 22 Oct 2023 12:51:20 +0200 Subject: [PATCH 050/466] Fix chunkSource mappings on 1.19.4 (#2469) fix chunkSource mappings on 1.19.4 --- .../adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java index 7e2f3eaee..17b354535 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java @@ -152,7 +152,7 @@ public class PaperweightRegen extends Regenerator Date: Sun, 22 Oct 2023 16:29:38 +0200 Subject: [PATCH 051/466] Avoid premature trimming in RegionIntersection (#2471) avoid premature trimming --- .../sk89q/worldedit/regions/RegionIntersection.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java index 8298a8b00..7a3e91343 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java @@ -164,14 +164,23 @@ public class RegionIntersection extends AbstractRegion { int bz = chunk.getZ() << 4; int tx = bx + 15; int tz = bz + 15; + List intersecting = new ArrayList<>(2); for (Region region : regions) { BlockVector3 regMin = region.getMinimumPoint(); BlockVector3 regMax = region.getMaximumPoint(); if (tx >= regMin.getX() && bx <= regMax.getX() && tz >= regMin.getZ() && bz <= regMax.getZ()) { - return region.processSet(chunk, get, set); + intersecting.add(region); } } - return null; + if (intersecting.isEmpty()) { + return null; + } + if (intersecting.size() == 1) { + return intersecting.get(0).processSet(chunk, get, set); + } + // if multiple regions intersect with this chunk, we must be more careful, otherwise one region might trim content of + // another region + return super.processSet(chunk, get, set); } @Override From 50cc9bc528ec61d5b321668d6901878c1f0608e2 Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 23 Oct 2023 15:40:38 +0100 Subject: [PATCH 052/466] fix: clear player's history away from main thread if lock locked (#2457) * fix: clear player's history away from main thread if lock locked - addresses crashing of #2448 * Correct lock usage * remove possibility for race condition --- .../java/com/sk89q/worldedit/LocalSession.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index 3391bad80..ae62a4f73 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -33,6 +33,7 @@ import com.fastasyncworldedit.core.limit.FaweLimit; import com.fastasyncworldedit.core.util.BrushCache; import com.fastasyncworldedit.core.util.MainUtil; import com.fastasyncworldedit.core.util.StringMan; +import com.fastasyncworldedit.core.util.TaskManager; import com.fastasyncworldedit.core.util.TextureHolder; import com.fastasyncworldedit.core.util.TextureUtil; import com.fastasyncworldedit.core.wrappers.WorldWrapper; @@ -143,7 +144,7 @@ public class LocalSession implements TextureHolder { } }); private transient volatile Integer historyNegativeIndex; - private transient final Lock historyWriteLock = new ReentrantLock(true); + private transient final ReentrantLock historyWriteLock = new ReentrantLock(true); private final transient Int2ObjectOpenHashMap tools = new Int2ObjectOpenHashMap<>(0); private transient Mask sourceMask; private transient TextureUtil texture; @@ -405,6 +406,19 @@ public class LocalSession implements TextureHolder { */ public void clearHistory() { //FAWE start + if (Fawe.isMainThread() && !historyWriteLock.tryLock()) { + // Do not make main thread wait if we cannot immediately clear history (on player logout usually) + TaskManager.taskManager().async(this::clearHistoryTask); + return; + } + try { + clearHistoryTask(); + } finally { + historyWriteLock.unlock(); + } + } + + private void clearHistoryTask() { historyWriteLock.lock(); try { // Ensure that changesets are properly removed @@ -420,8 +434,8 @@ public class LocalSession implements TextureHolder { save(); historySize = 0; currentWorld = null; - //FAWE end } + //FAWE end /** * Remember an edit session for the undo history. If the history maximum From 0566bd359ebb8bd2508d31d3ad283a044c028952 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Tue, 24 Oct 2023 16:46:20 +0100 Subject: [PATCH 053/466] fix cursed 1.20.2 adapters ...what even how did this build?? --- .../adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java | 7 ++----- .../ext/fawe/v1_20_R2/PaperweightDataConverters.java | 5 ++--- .../adapter/ext/fawe/v1_20_R2/PaperweightFakePlayer.java | 2 +- .../ext/fawe/v1_20_R2/PaperweightWorldNativeAccess.java | 6 +++--- .../adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java | 5 ++--- 5 files changed, 10 insertions(+), 15 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java index 38b0701d4..b73e6d06e 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2; +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R2; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; @@ -28,8 +28,6 @@ import com.google.common.util.concurrent.Futures; import com.mojang.datafixers.util.Either; import com.mojang.serialization.Lifecycle; import com.sk89q.jnbt.NBTConstants; -import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R2.PaperweightDataConverters; -import com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2.PaperweightFakePlayer; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; @@ -358,8 +356,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter createWorldNativeAccess(org.bukkit.World world) { - return new com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2.PaperweightWorldNativeAccess(this, - new WeakReference<>(((CraftWorld) world).getHandle())); + return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle())); } private static net.minecraft.core.Direction adapt(Direction face) { diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightDataConverters.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightDataConverters.java index af49e2809..f7be01738 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightDataConverters.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightDataConverters.java @@ -168,7 +168,7 @@ public class PaperweightDataConverters extends DataFixerBuilder implements com.s .getValue().getAsString(); } - private final com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2.PaperweightAdapter adapter; + private final PaperweightAdapter adapter; private static final NbtOps OPS_NBT = NbtOps.INSTANCE; private static final int LEGACY_VERSION = 1343; @@ -204,8 +204,7 @@ public class PaperweightDataConverters extends DataFixerBuilder implements com.s } } - public PaperweightDataConverters(int dataVersion, - com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2.PaperweightAdapter adapter) { + public PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { super(dataVersion); DATA_VERSION = dataVersion; INSTANCE = this; diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightFakePlayer.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightFakePlayer.java index f05eebe0c..c6d0b936c 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightFakePlayer.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightFakePlayer.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2; +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R2; import com.mojang.authlib.GameProfile; import net.minecraft.network.chat.Component; diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightWorldNativeAccess.java index ac5baa35f..9e69e4a31 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightWorldNativeAccess.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightWorldNativeAccess.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2; +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R2; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.internal.block.BlockStateIdAccess; @@ -43,11 +43,11 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess world; private SideEffectSet sideEffectSet; - public PaperweightWorldNativeAccess(com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2.PaperweightAdapter adapter, WeakReference world) { + public PaperweightWorldNativeAccess(PaperweightAdapter adapter, WeakReference world) { this.adapter = adapter; this.world = world; } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java index a9e657b2e..48bc935cb 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java @@ -20,7 +20,6 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.v1_20_R2.PaperweightAdapter; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.regen.PaperweightRegen; import com.sk89q.worldedit.entity.BaseEntity; @@ -124,7 +123,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements } } - private final PaperweightAdapter parent; + private final com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R2.PaperweightAdapter parent; // ------------------------------------------------------------------------ // Code that may break between versions of Minecraft // ------------------------------------------------------------------------ @@ -135,7 +134,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements private Map>> allBlockProperties = null; public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { - this.parent = new PaperweightAdapter(); + this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R2.PaperweightAdapter(); } @Nullable From 256ef744528abeaaef639b4ae4f8ec22c5ba3896 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Thu, 26 Oct 2023 21:14:27 +0200 Subject: [PATCH 054/466] Cleanup rawtypes warnings in relighting code (#2472) remove unneeded generic type --- .../fawe/v1_17_R1_2/PaperweightStarlightRelighter.java | 4 +--- .../v1_17_R1_2/PaperweightStarlightRelighterFactory.java | 5 +---- .../impl/fawe/v1_18_R2/PaperweightStarlightRelighter.java | 4 +--- .../v1_18_R2/PaperweightStarlightRelighterFactory.java | 5 +---- .../impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java | 4 +--- .../v1_19_R3/PaperweightStarlightRelighterFactory.java | 5 +---- .../impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java | 4 +--- .../v1_20_R1/PaperweightStarlightRelighterFactory.java | 5 +---- .../impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java | 4 +--- .../v1_20_R2/PaperweightStarlightRelighterFactory.java | 5 +---- .../bukkit/adapter/NMSRelighterFactory.java | 4 +--- .../core/extent/processor/lighting/NMSRelighter.java | 8 +++----- .../core/extent/processor/lighting/RelighterFactory.java | 3 +-- 13 files changed, 15 insertions(+), 45 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighter.java index 8298be6f1..d80c82aa2 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighter.java @@ -3,7 +3,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter; import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; -import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.TaskManager; @@ -70,8 +69,7 @@ public class PaperweightStarlightRelighter implements Relighter { private final ReentrantLock areaLock = new ReentrantLock(); private final NMSRelighter delegate; - @SuppressWarnings("rawtypes") - public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { + public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { this.serverLevel = serverLevel; this.delegate = new NMSRelighter(queue); } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighterFactory.java index 2672c5b62..9cd0a1ef8 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighterFactory.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighterFactory.java @@ -4,7 +4,6 @@ import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.sk89q.worldedit.world.World; import org.bukkit.Bukkit; @@ -15,9 +14,7 @@ import javax.annotation.Nonnull; public class PaperweightStarlightRelighterFactory implements RelighterFactory { @Override - public @Nonnull - @SuppressWarnings("rawtypes") - Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { + public @Nonnull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { org.bukkit.World w = Bukkit.getWorld(world.getName()); if (w == null) { return NullRelighter.INSTANCE; diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighter.java index 397931bc5..0e27ec7ee 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighter.java @@ -3,7 +3,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter; import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; -import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.TaskManager; @@ -45,8 +44,7 @@ public class PaperweightStarlightRelighter implements Relighter { private final ReentrantLock areaLock = new ReentrantLock(); private final NMSRelighter delegate; - @SuppressWarnings("rawtypes") - public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { + public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { this.serverLevel = serverLevel; this.delegate = new NMSRelighter(queue); } diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighterFactory.java index 960174342..735bcc677 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighterFactory.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighterFactory.java @@ -4,7 +4,6 @@ import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.sk89q.worldedit.world.World; import org.bukkit.Bukkit; @@ -15,9 +14,7 @@ import javax.annotation.Nonnull; public class PaperweightStarlightRelighterFactory implements RelighterFactory { @Override - public @Nonnull - @SuppressWarnings("rawtypes") - Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { + public @Nonnull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { org.bukkit.World w = Bukkit.getWorld(world.getName()); if (w == null) { return NullRelighter.INSTANCE; diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java index 62d781212..7fe32f616 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java @@ -3,7 +3,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter; import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; -import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.TaskManager; @@ -45,8 +44,7 @@ public class PaperweightStarlightRelighter implements Relighter { private final ReentrantLock areaLock = new ReentrantLock(); private final NMSRelighter delegate; - @SuppressWarnings("rawtypes") - public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { + public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { this.serverLevel = serverLevel; this.delegate = new NMSRelighter(queue); } diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighterFactory.java index ad525f242..78c623c7a 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighterFactory.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighterFactory.java @@ -4,7 +4,6 @@ import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.sk89q.worldedit.world.World; import org.bukkit.Bukkit; @@ -15,9 +14,7 @@ import javax.annotation.Nonnull; public class PaperweightStarlightRelighterFactory implements RelighterFactory { @Override - public @Nonnull - @SuppressWarnings("rawtypes") - Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { + public @Nonnull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { org.bukkit.World w = Bukkit.getWorld(world.getName()); if (w == null) { return NullRelighter.INSTANCE; diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java index 2cc67360b..235078ee0 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java @@ -3,7 +3,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter; import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; -import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.TaskManager; @@ -45,8 +44,7 @@ public class PaperweightStarlightRelighter implements Relighter { private final ReentrantLock areaLock = new ReentrantLock(); private final NMSRelighter delegate; - @SuppressWarnings("rawtypes") - public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { + public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { this.serverLevel = serverLevel; this.delegate = new NMSRelighter(queue); } diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighterFactory.java index e2658ee0e..83509a2bb 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighterFactory.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighterFactory.java @@ -4,7 +4,6 @@ import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.sk89q.worldedit.world.World; import org.bukkit.Bukkit; @@ -15,9 +14,7 @@ import javax.annotation.Nonnull; public class PaperweightStarlightRelighterFactory implements RelighterFactory { @Override - public @Nonnull - @SuppressWarnings("rawtypes") - Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { + public @Nonnull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { org.bukkit.World w = Bukkit.getWorld(world.getName()); if (w == null) { return NullRelighter.INSTANCE; diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java index 6c6527c02..d02b784e8 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java @@ -3,7 +3,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter; import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; -import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.TaskManager; @@ -45,8 +44,7 @@ public class PaperweightStarlightRelighter implements Relighter { private final ReentrantLock areaLock = new ReentrantLock(); private final NMSRelighter delegate; - @SuppressWarnings("rawtypes") - public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { + public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { this.serverLevel = serverLevel; this.delegate = new NMSRelighter(queue); } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighterFactory.java index 4e5b9b7ff..4afc48689 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighterFactory.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighterFactory.java @@ -4,7 +4,6 @@ import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.sk89q.worldedit.world.World; import org.bukkit.Bukkit; @@ -15,9 +14,7 @@ import javax.annotation.Nonnull; public class PaperweightStarlightRelighterFactory implements RelighterFactory { @Override - public @Nonnull - @SuppressWarnings("rawtypes") - Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { + public @Nonnull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { org.bukkit.World w = Bukkit.getWorld(world.getName()); if (w == null) { return NullRelighter.INSTANCE; diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSRelighterFactory.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSRelighterFactory.java index 4fd78df85..39c327991 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSRelighterFactory.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSRelighterFactory.java @@ -5,7 +5,6 @@ import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter; import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.sk89q.worldedit.world.World; @@ -14,8 +13,7 @@ import javax.annotation.Nonnull; public class NMSRelighterFactory implements RelighterFactory { @Override - public @Nonnull - Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { + public @Nonnull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { return new NMSRelighter( queue, relightMode != null ? relightMode : RelightMode.valueOf(Settings.settings().LIGHTING.MODE) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/NMSRelighter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/NMSRelighter.java index 97a97f9a7..e38df12f5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/NMSRelighter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/NMSRelighter.java @@ -4,7 +4,6 @@ import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.math.BlockVectorSet; import com.fastasyncworldedit.core.math.MutableBlockVector3; -import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.fastasyncworldedit.core.queue.implementation.chunk.ChunkHolder; import com.fastasyncworldedit.core.util.MathMan; @@ -34,7 +33,6 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; -@SuppressWarnings("rawtypes") public class NMSRelighter implements Relighter { private static final int DISPATCH_SIZE = 64; @@ -51,7 +49,7 @@ public class NMSRelighter implements Relighter { } public final MutableBlockVector3 mutableBlockPos = new MutableBlockVector3(0, 0, 0); - private final IQueueExtent queue; + private final IQueueExtent queue; private final Map skyToRelight; private final Object present = new Object(); private final Map chunksToSend; @@ -66,11 +64,11 @@ public class NMSRelighter implements Relighter { private final AtomicBoolean finished = new AtomicBoolean(false); private boolean removeFirst; - public NMSRelighter(IQueueExtent queue) { + public NMSRelighter(IQueueExtent queue) { this(queue, null); } - public NMSRelighter(IQueueExtent queue, RelightMode relightMode) { + public NMSRelighter(IQueueExtent queue, RelightMode relightMode) { this.queue = queue; this.skyToRelight = new Long2ObjectOpenHashMap<>(12); this.lightQueue = new Long2ObjectOpenHashMap<>(12); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/RelighterFactory.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/RelighterFactory.java index 34275f77d..f0bca36ed 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/RelighterFactory.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/RelighterFactory.java @@ -1,6 +1,5 @@ package com.fastasyncworldedit.core.extent.processor.lighting; -import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.sk89q.worldedit.world.World; @@ -25,6 +24,6 @@ public interface RelighterFactory { * @return a new Relighter instance with the specified settings. */ @Nonnull - Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue); + Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue); } From 36a892eb376d129eaa1077b501d9ad02c8afcae5 Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 26 Oct 2023 20:14:39 +0100 Subject: [PATCH 055/466] fix: chunks should only be initialised in the getOrCreateChunk method (#2462) --- .../java/com/fastasyncworldedit/core/queue/IQueueExtent.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java index a5a29f170..01503ad55 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java @@ -135,9 +135,6 @@ public interface IQueueExtent extends Flushable, Trimable, ICh return block; } T chunk = this.getOrCreateChunk(chunkX, chunkZ); - // Initialize - chunk.init(this, chunkX, chunkZ); - chunk.setFastMode(isFastMode()); T newChunk = filter.applyChunk(chunk, region); if (newChunk != null) { From b8434f891ed733eea4f8a6ef3507d423d33d17a1 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sun, 29 Oct 2023 10:55:50 +0100 Subject: [PATCH 056/466] Reduce duplicated singleton objects (#2473) --- .../java/com/fastasyncworldedit/core/FaweCache.java | 11 ++++++----- .../core/configuration/Settings.java | 6 +++--- .../fastasyncworldedit/core/database/DBHandler.java | 2 +- .../com/fastasyncworldedit/core/util/WEManager.java | 2 +- .../sk89q/worldedit/command/HistorySubCommands.java | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java index d8e1474e6..0655e4214 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java @@ -60,16 +60,17 @@ import java.util.function.Supplier; import static com.google.common.base.Preconditions.checkNotNull; public enum FaweCache implements Trimable { - /** - * @deprecated Use {@link #INSTANCE} to get an instance. - */ - @Deprecated(forRemoval = true, since = "2.0.0") - IMP, /** * @since 2.0.0 */ INSTANCE; + /** + * @deprecated Use {@link #INSTANCE} to get an instance. + */ + @Deprecated(forRemoval = true, since = "2.0.0") + public static final FaweCache IMP = INSTANCE; + private static final Logger LOGGER = LogManagerCompat.getLogger(); public final int BLOCKS_PER_LAYER = 4096; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index d0aeb5058..672dcebe8 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -19,14 +19,14 @@ import java.util.stream.Stream; public class Settings extends Config { + @Ignore + static Settings INSTANCE = new Settings(); /** * @deprecated Use {@link #settings()} instead to get an instance. */ @Ignore @Deprecated(forRemoval = true, since = "2.0.0") - public static final Settings IMP = new Settings(); - @Ignore - static Settings INSTANCE = new Settings(); + public static final Settings IMP = INSTANCE; @Ignore public boolean PROTOCOL_SUPPORT_FIX = false; @Comment("These first 6 aren't configurable") // This is a comment diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/DBHandler.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/DBHandler.java index fd1263b11..755e94b2f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/DBHandler.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/DBHandler.java @@ -13,7 +13,7 @@ public class DBHandler { * @deprecated Use {@link #dbHandler()} instead. */ @Deprecated(forRemoval = true, since = "2.0.0") - public static final DBHandler IMP = new DBHandler(); + public static final DBHandler IMP = dbHandler(); private static final Logger LOGGER = LogManagerCompat.getLogger(); private static DBHandler INSTANCE; private final Map databases = new ConcurrentHashMap<>(8, 0.9f, 1); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/WEManager.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/WEManager.java index 17b7882f2..b31853dd0 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/WEManager.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/WEManager.java @@ -32,7 +32,7 @@ public class WEManager { * @deprecated Use {@link #weManager()} instead. */ @Deprecated(forRemoval = true, since = "2.0.0") - public static WEManager IMP = new WEManager(); + public static WEManager IMP = weManager(); private final ArrayDeque managers = new ArrayDeque<>(); /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java index 452d5084c..6b30e9e7e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java @@ -201,7 +201,7 @@ public class HistorySubCommands { .at(summary.maxX, world.getMaxY(), summary.maxZ) ); rollback.setTime(historyFile.lastModified()); - RollbackDatabase db = DBHandler.IMP + RollbackDatabase db = DBHandler.dbHandler() .getDatabase(world); db.logEdit(rollback); actor.print(TextComponent.of("Logging: " + historyFile)); From 6bd13828725a398c5bf83230fa8c5e467789ac0c Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Tue, 31 Oct 2023 21:00:46 +0100 Subject: [PATCH 057/466] Reuse starlight relighting code across versions (#2474) --- .../PaperweightStarlightRelighter.java | 182 +++------------- .../PaperweightStarlightRelighter.java | 161 ++------------ .../PaperweightStarlightRelighter.java | 161 ++------------ .../PaperweightStarlightRelighter.java | 161 ++------------ .../PaperweightStarlightRelighter.java | 161 ++------------ .../bukkit/adapter/StarlightRelighter.java | 196 ++++++++++++++++++ 6 files changed, 293 insertions(+), 729 deletions(-) create mode 100644 worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/StarlightRelighter.java diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighter.java index d80c82aa2..ea2afede3 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighter.java @@ -1,16 +1,8 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; +import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter; -import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; import com.fastasyncworldedit.core.queue.IQueueExtent; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.TaskManager; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -import it.unimi.dsi.fastutil.longs.LongArraySet; -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.longs.LongSet; import net.minecraft.server.MCUtil; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ThreadedLevelLightEngine; @@ -18,27 +10,18 @@ import net.minecraft.server.level.TicketType; import net.minecraft.util.Unit; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.chunk.ChunkStatus; -import org.apache.logging.log4j.Logger; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import java.util.function.IntConsumer; -public class PaperweightStarlightRelighter implements Relighter { - - public static final MethodHandle RELIGHT; - private static final Logger LOGGER = LogManagerCompat.getLogger(); - private static final int CHUNKS_PER_BATCH = 1024; // 32 * 32 - private static final int CHUNKS_PER_BATCH_SQRT_LOG2 = 5; // for shifting +public class PaperweightStarlightRelighter extends StarlightRelighter { + private static final MethodHandle RELIGHT; private static final TicketType FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); private static final int LIGHT_LEVEL = MCUtil.getTicketLevelFor(ChunkStatus.LIGHT); @@ -57,21 +40,36 @@ public class PaperweightStarlightRelighter implements Relighter { IntConsumer.class ) ); + tmp = MethodHandles.dropReturn(tmp); } catch (NoSuchMethodException | IllegalAccessException e) { LOGGER.error("Failed to locate 'relight' method in ThreadedLevelLightEngine. Is everything up to date?", e); } RELIGHT = tmp; } - private final ServerLevel serverLevel; - private final ReentrantLock lock = new ReentrantLock(); - private final Long2ObjectLinkedOpenHashMap regions = new Long2ObjectLinkedOpenHashMap<>(); - private final ReentrantLock areaLock = new ReentrantLock(); - private final NMSRelighter delegate; - public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { - this.serverLevel = serverLevel; - this.delegate = new NMSRelighter(queue); + super(serverLevel, queue); + } + + @Override + protected ChunkPos createChunkPos(final long chunkKey) { + return new ChunkPos(chunkKey); + } + + @Override + protected long asLong(final int chunkX, final int chunkZ) { + return ChunkPos.asLong(chunkX, chunkZ); + } + + @Override + protected CompletableFuture chunkLoadFuture(final ChunkPos chunkPos) { + return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z) + .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( + FAWE_TICKET, + chunkPos, + LIGHT_LEVEL, + Unit.INSTANCE + )); } public static boolean isUsable() { @@ -79,95 +77,13 @@ public class PaperweightStarlightRelighter implements Relighter { } @Override - public boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask) { - areaLock.lock(); - try { - long key = MathMan.pairInt(cx >> CHUNKS_PER_BATCH_SQRT_LOG2, cz >> CHUNKS_PER_BATCH_SQRT_LOG2); - // TODO probably submit here already if chunks.size == CHUNKS_PER_BATCH? - LongSet chunks = this.regions.computeIfAbsent(key, k -> new LongArraySet(CHUNKS_PER_BATCH >> 2)); - chunks.add(ChunkPos.asLong(cx, cz)); - } finally { - areaLock.unlock(); - } - return true; - } - - @Override - public void addLightUpdate(int x, int y, int z) { - delegate.addLightUpdate(x, y, z); - } - - /* - * This method is called "recursively", iterating and removing elements - * from the regions linked map. This way, chunks are loaded in batches to avoid - * OOMEs. - */ - @Override - public void fixLightingSafe(boolean sky) { - this.areaLock.lock(); - try { - if (regions.isEmpty()) { - return; - } - LongSet first = regions.removeFirst(); - fixLighting(first, () -> fixLightingSafe(true)); - } finally { - this.areaLock.unlock(); - } - } - - /* - * Processes a set of chunks and runs an action afterwards. - * The action is run async, the chunks are partly processed on the main thread - * (as required by the server). - */ - private void fixLighting(LongSet chunks, Runnable andThen) { - // convert from long keys to ChunkPos - Set coords = new HashSet<>(); - LongIterator iterator = chunks.iterator(); - while (iterator.hasNext()) { - coords.add(new ChunkPos(iterator.nextLong())); - } - TaskManager.taskManager().task(() -> { - // trigger chunk load and apply ticket on main thread - List> futures = new ArrayList<>(); - for (ChunkPos pos : coords) { - futures.add(serverLevel.getWorld().getChunkAtAsync(pos.x, pos.z) - .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( - FAWE_TICKET, - pos, - LIGHT_LEVEL, - Unit.INSTANCE - )) - ); - } - // collect futures and trigger relight once all chunks are loaded - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(v -> - invokeRelight( - coords, - c -> { - }, // no callback for single chunks required - i -> { - if (i != coords.size()) { - LOGGER.warn("Processed {} chunks instead of {}", i, coords.size()); - } - // post process chunks on main thread - TaskManager.taskManager().task(() -> postProcessChunks(coords)); - // call callback on our own threads - TaskManager.taskManager().async(andThen); - } - ) - ); - }); - } - - private void invokeRelight( + protected void invokeRelight( Set coords, Consumer chunkCallback, IntConsumer processCallback ) { try { - int unused = (int) RELIGHT.invokeExact( + RELIGHT.invokeExact( serverLevel.getChunkSource().getLightEngine(), coords, chunkCallback, // callback per chunk @@ -182,7 +98,7 @@ public class PaperweightStarlightRelighter implements Relighter { * Allow the server to unload the chunks again. * Also, if chunk packets are sent delayed, we need to do that here */ - private void postProcessChunks(Set coords) { + protected void postProcessChunks(Set coords) { boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING; for (ChunkPos pos : coords) { int x = pos.x; @@ -194,44 +110,4 @@ public class PaperweightStarlightRelighter implements Relighter { } } - @Override - public void clear() { - - } - - @Override - public void removeLighting() { - this.delegate.removeLighting(); - } - - @Override - public void fixBlockLighting() { - fixLightingSafe(true); - } - - @Override - public void fixSkyLighting() { - fixLightingSafe(true); - } - - @Override - public boolean isEmpty() { - return true; - } - - @Override - public ReentrantLock getLock() { - return this.lock; - } - - @Override - public boolean isFinished() { - return false; - } - - @Override - public void close() throws Exception { - fixLightingSafe(true); - } - } diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighter.java index 0e27ec7ee..c832fc98a 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighter.java @@ -1,138 +1,51 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; +import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter; -import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; import com.fastasyncworldedit.core.queue.IQueueExtent; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.TaskManager; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -import it.unimi.dsi.fastutil.longs.LongArraySet; -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.longs.LongSet; import net.minecraft.server.MCUtil; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.TicketType; import net.minecraft.util.Unit; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.chunk.ChunkStatus; -import org.apache.logging.log4j.Logger; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import java.util.function.IntConsumer; -public class PaperweightStarlightRelighter implements Relighter { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - private static final int CHUNKS_PER_BATCH = 1024; // 32 * 32 - private static final int CHUNKS_PER_BATCH_SQRT_LOG2 = 5; // for shifting +public class PaperweightStarlightRelighter extends StarlightRelighter { private static final TicketType FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); private static final int LIGHT_LEVEL = MCUtil.getTicketLevelFor(ChunkStatus.LIGHT); - - private final ServerLevel serverLevel; - private final ReentrantLock lock = new ReentrantLock(); - private final Long2ObjectLinkedOpenHashMap regions = new Long2ObjectLinkedOpenHashMap<>(); - private final ReentrantLock areaLock = new ReentrantLock(); - private final NMSRelighter delegate; - public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { - this.serverLevel = serverLevel; - this.delegate = new NMSRelighter(queue); + super(serverLevel, queue); } @Override - public boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask) { - areaLock.lock(); - try { - long key = MathMan.pairInt(cx >> CHUNKS_PER_BATCH_SQRT_LOG2, cz >> CHUNKS_PER_BATCH_SQRT_LOG2); - // TODO probably submit here already if chunks.size == CHUNKS_PER_BATCH? - LongSet chunks = this.regions.computeIfAbsent(key, k -> new LongArraySet(CHUNKS_PER_BATCH >> 2)); - chunks.add(ChunkPos.asLong(cx, cz)); - } finally { - areaLock.unlock(); - } - return true; + protected ChunkPos createChunkPos(final long chunkKey) { + return new ChunkPos(chunkKey); } @Override - public void addLightUpdate(int x, int y, int z) { - delegate.addLightUpdate(x, y, z); + protected long asLong(final int chunkX, final int chunkZ) { + return ChunkPos.asLong(chunkX, chunkZ); } - /* - * This method is called "recursively", iterating and removing elements - * from the regions linked map. This way, chunks are loaded in batches to avoid - * OOMEs. - */ @Override - public void fixLightingSafe(boolean sky) { - this.areaLock.lock(); - try { - if (regions.isEmpty()) { - return; - } - LongSet first = regions.removeFirst(); - fixLighting(first, () -> fixLightingSafe(true)); - } finally { - this.areaLock.unlock(); - } + protected CompletableFuture chunkLoadFuture(final ChunkPos chunkPos) { + return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z) + .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( + FAWE_TICKET, + chunkPos, + LIGHT_LEVEL, + Unit.INSTANCE + )); } - /* - * Processes a set of chunks and runs an action afterwards. - * The action is run async, the chunks are partly processed on the main thread - * (as required by the server). - */ - private void fixLighting(LongSet chunks, Runnable andThen) { - // convert from long keys to ChunkPos - Set coords = new HashSet<>(); - LongIterator iterator = chunks.iterator(); - while (iterator.hasNext()) { - coords.add(new ChunkPos(iterator.nextLong())); - } - TaskManager.taskManager().task(() -> { - // trigger chunk load and apply ticket on main thread - List> futures = new ArrayList<>(); - for (ChunkPos pos : coords) { - futures.add(serverLevel.getWorld().getChunkAtAsync(pos.x, pos.z) - .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( - FAWE_TICKET, - pos, - LIGHT_LEVEL, - Unit.INSTANCE - )) - ); - } - // collect futures and trigger relight once all chunks are loaded - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(v -> - invokeRelight( - coords, - c -> { - }, // no callback for single chunks required - i -> { - if (i != coords.size()) { - LOGGER.warn("Processed {} chunks instead of {}", i, coords.size()); - } - // post process chunks on main thread - TaskManager.taskManager().task(() -> postProcessChunks(coords)); - // call callback on our own threads - TaskManager.taskManager().async(andThen); - } - ) - ); - }); - } - - private void invokeRelight( + protected void invokeRelight( Set coords, Consumer chunkCallback, IntConsumer processCallback @@ -148,7 +61,7 @@ public class PaperweightStarlightRelighter implements Relighter { * Allow the server to unload the chunks again. * Also, if chunk packets are sent delayed, we need to do that here */ - private void postProcessChunks(Set coords) { + protected void postProcessChunks(Set coords) { boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING; for (ChunkPos pos : coords) { int x = pos.x; @@ -160,44 +73,4 @@ public class PaperweightStarlightRelighter implements Relighter { } } - @Override - public void clear() { - - } - - @Override - public void removeLighting() { - this.delegate.removeLighting(); - } - - @Override - public void fixBlockLighting() { - fixLightingSafe(true); - } - - @Override - public void fixSkyLighting() { - fixLightingSafe(true); - } - - @Override - public boolean isEmpty() { - return true; - } - - @Override - public ReentrantLock getLock() { - return this.lock; - } - - @Override - public boolean isFinished() { - return false; - } - - @Override - public void close() throws Exception { - fixLightingSafe(true); - } - } diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java index 7fe32f616..580bbf5a6 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java @@ -1,138 +1,51 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; +import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter; -import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; import com.fastasyncworldedit.core.queue.IQueueExtent; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.TaskManager; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -import it.unimi.dsi.fastutil.longs.LongArraySet; -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.longs.LongSet; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.TicketType; import net.minecraft.util.Unit; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.chunk.ChunkStatus; -import org.apache.logging.log4j.Logger; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import java.util.function.IntConsumer; -public class PaperweightStarlightRelighter implements Relighter { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - private static final int CHUNKS_PER_BATCH = 1024; // 32 * 32 - private static final int CHUNKS_PER_BATCH_SQRT_LOG2 = 5; // for shifting +public class PaperweightStarlightRelighter extends StarlightRelighter { private static final TicketType FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkStatus.getDistance(ChunkStatus.LIGHT); - - private final ServerLevel serverLevel; - private final ReentrantLock lock = new ReentrantLock(); - private final Long2ObjectLinkedOpenHashMap regions = new Long2ObjectLinkedOpenHashMap<>(); - private final ReentrantLock areaLock = new ReentrantLock(); - private final NMSRelighter delegate; - public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { - this.serverLevel = serverLevel; - this.delegate = new NMSRelighter(queue); + super(serverLevel, queue); } @Override - public boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask) { - areaLock.lock(); - try { - long key = MathMan.pairInt(cx >> CHUNKS_PER_BATCH_SQRT_LOG2, cz >> CHUNKS_PER_BATCH_SQRT_LOG2); - // TODO probably submit here already if chunks.size == CHUNKS_PER_BATCH? - LongSet chunks = this.regions.computeIfAbsent(key, k -> new LongArraySet(CHUNKS_PER_BATCH >> 2)); - chunks.add(ChunkPos.asLong(cx, cz)); - } finally { - areaLock.unlock(); - } - return true; + protected ChunkPos createChunkPos(final long chunkKey) { + return new ChunkPos(chunkKey); } @Override - public void addLightUpdate(int x, int y, int z) { - delegate.addLightUpdate(x, y, z); + protected long asLong(final int chunkX, final int chunkZ) { + return ChunkPos.asLong(chunkX, chunkZ); } - /* - * This method is called "recursively", iterating and removing elements - * from the regions linked map. This way, chunks are loaded in batches to avoid - * OOMEs. - */ @Override - public void fixLightingSafe(boolean sky) { - this.areaLock.lock(); - try { - if (regions.isEmpty()) { - return; - } - LongSet first = regions.removeFirst(); - fixLighting(first, () -> fixLightingSafe(true)); - } finally { - this.areaLock.unlock(); - } + protected CompletableFuture chunkLoadFuture(final ChunkPos chunkPos) { + return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z) + .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( + FAWE_TICKET, + chunkPos, + LIGHT_LEVEL, + Unit.INSTANCE + )); } - /* - * Processes a set of chunks and runs an action afterwards. - * The action is run async, the chunks are partly processed on the main thread - * (as required by the server). - */ - private void fixLighting(LongSet chunks, Runnable andThen) { - // convert from long keys to ChunkPos - Set coords = new HashSet<>(); - LongIterator iterator = chunks.iterator(); - while (iterator.hasNext()) { - coords.add(new ChunkPos(iterator.nextLong())); - } - TaskManager.taskManager().task(() -> { - // trigger chunk load and apply ticket on main thread - List> futures = new ArrayList<>(); - for (ChunkPos pos : coords) { - futures.add(serverLevel.getWorld().getChunkAtAsync(pos.x, pos.z) - .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( - FAWE_TICKET, - pos, - LIGHT_LEVEL, - Unit.INSTANCE - )) - ); - } - // collect futures and trigger relight once all chunks are loaded - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(v -> - invokeRelight( - coords, - c -> { - }, // no callback for single chunks required - i -> { - if (i != coords.size()) { - LOGGER.warn("Processed {} chunks instead of {}", i, coords.size()); - } - // post process chunks on main thread - TaskManager.taskManager().task(() -> postProcessChunks(coords)); - // call callback on our own threads - TaskManager.taskManager().async(andThen); - } - ) - ); - }); - } - - private void invokeRelight( + protected void invokeRelight( Set coords, Consumer chunkCallback, IntConsumer processCallback @@ -148,7 +61,7 @@ public class PaperweightStarlightRelighter implements Relighter { * Allow the server to unload the chunks again. * Also, if chunk packets are sent delayed, we need to do that here */ - private void postProcessChunks(Set coords) { + protected void postProcessChunks(Set coords) { boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING; for (ChunkPos pos : coords) { int x = pos.x; @@ -160,44 +73,4 @@ public class PaperweightStarlightRelighter implements Relighter { } } - @Override - public void clear() { - - } - - @Override - public void removeLighting() { - this.delegate.removeLighting(); - } - - @Override - public void fixBlockLighting() { - fixLightingSafe(true); - } - - @Override - public void fixSkyLighting() { - fixLightingSafe(true); - } - - @Override - public boolean isEmpty() { - return true; - } - - @Override - public ReentrantLock getLock() { - return this.lock; - } - - @Override - public boolean isFinished() { - return false; - } - - @Override - public void close() throws Exception { - fixLightingSafe(true); - } - } diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java index 235078ee0..30df91459 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java @@ -1,138 +1,51 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; +import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter; -import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; import com.fastasyncworldedit.core.queue.IQueueExtent; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.TaskManager; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -import it.unimi.dsi.fastutil.longs.LongArraySet; -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.longs.LongSet; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.TicketType; import net.minecraft.util.Unit; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.chunk.ChunkStatus; -import org.apache.logging.log4j.Logger; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import java.util.function.IntConsumer; -public class PaperweightStarlightRelighter implements Relighter { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - private static final int CHUNKS_PER_BATCH = 1024; // 32 * 32 - private static final int CHUNKS_PER_BATCH_SQRT_LOG2 = 5; // for shifting +public class PaperweightStarlightRelighter extends StarlightRelighter { private static final TicketType FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkStatus.getDistance(ChunkStatus.LIGHT); - - private final ServerLevel serverLevel; - private final ReentrantLock lock = new ReentrantLock(); - private final Long2ObjectLinkedOpenHashMap regions = new Long2ObjectLinkedOpenHashMap<>(); - private final ReentrantLock areaLock = new ReentrantLock(); - private final NMSRelighter delegate; - public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { - this.serverLevel = serverLevel; - this.delegate = new NMSRelighter(queue); + super(serverLevel, queue); } @Override - public boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask) { - areaLock.lock(); - try { - long key = MathMan.pairInt(cx >> CHUNKS_PER_BATCH_SQRT_LOG2, cz >> CHUNKS_PER_BATCH_SQRT_LOG2); - // TODO probably submit here already if chunks.size == CHUNKS_PER_BATCH? - LongSet chunks = this.regions.computeIfAbsent(key, k -> new LongArraySet(CHUNKS_PER_BATCH >> 2)); - chunks.add(ChunkPos.asLong(cx, cz)); - } finally { - areaLock.unlock(); - } - return true; + protected ChunkPos createChunkPos(final long chunkKey) { + return new ChunkPos(chunkKey); } @Override - public void addLightUpdate(int x, int y, int z) { - delegate.addLightUpdate(x, y, z); + protected long asLong(final int chunkX, final int chunkZ) { + return ChunkPos.asLong(chunkX, chunkZ); } - /* - * This method is called "recursively", iterating and removing elements - * from the regions linked map. This way, chunks are loaded in batches to avoid - * OOMEs. - */ @Override - public void fixLightingSafe(boolean sky) { - this.areaLock.lock(); - try { - if (regions.isEmpty()) { - return; - } - LongSet first = regions.removeFirst(); - fixLighting(first, () -> fixLightingSafe(true)); - } finally { - this.areaLock.unlock(); - } + protected CompletableFuture chunkLoadFuture(final ChunkPos chunkPos) { + return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z) + .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( + FAWE_TICKET, + chunkPos, + LIGHT_LEVEL, + Unit.INSTANCE + )); } - /* - * Processes a set of chunks and runs an action afterwards. - * The action is run async, the chunks are partly processed on the main thread - * (as required by the server). - */ - private void fixLighting(LongSet chunks, Runnable andThen) { - // convert from long keys to ChunkPos - Set coords = new HashSet<>(); - LongIterator iterator = chunks.iterator(); - while (iterator.hasNext()) { - coords.add(new ChunkPos(iterator.nextLong())); - } - TaskManager.taskManager().task(() -> { - // trigger chunk load and apply ticket on main thread - List> futures = new ArrayList<>(); - for (ChunkPos pos : coords) { - futures.add(serverLevel.getWorld().getChunkAtAsync(pos.x, pos.z) - .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( - FAWE_TICKET, - pos, - LIGHT_LEVEL, - Unit.INSTANCE - )) - ); - } - // collect futures and trigger relight once all chunks are loaded - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(v -> - invokeRelight( - coords, - c -> { - }, // no callback for single chunks required - i -> { - if (i != coords.size()) { - LOGGER.warn("Processed {} chunks instead of {}", i, coords.size()); - } - // post process chunks on main thread - TaskManager.taskManager().task(() -> postProcessChunks(coords)); - // call callback on our own threads - TaskManager.taskManager().async(andThen); - } - ) - ); - }); - } - - private void invokeRelight( + protected void invokeRelight( Set coords, Consumer chunkCallback, IntConsumer processCallback @@ -148,7 +61,7 @@ public class PaperweightStarlightRelighter implements Relighter { * Allow the server to unload the chunks again. * Also, if chunk packets are sent delayed, we need to do that here */ - private void postProcessChunks(Set coords) { + protected void postProcessChunks(Set coords) { boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING; for (ChunkPos pos : coords) { int x = pos.x; @@ -160,44 +73,4 @@ public class PaperweightStarlightRelighter implements Relighter { } } - @Override - public void clear() { - - } - - @Override - public void removeLighting() { - this.delegate.removeLighting(); - } - - @Override - public void fixBlockLighting() { - fixLightingSafe(true); - } - - @Override - public void fixSkyLighting() { - fixLightingSafe(true); - } - - @Override - public boolean isEmpty() { - return true; - } - - @Override - public ReentrantLock getLock() { - return this.lock; - } - - @Override - public boolean isFinished() { - return false; - } - - @Override - public void close() throws Exception { - fixLightingSafe(true); - } - } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java index d02b784e8..e869046da 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java @@ -1,138 +1,51 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; +import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter; -import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; import com.fastasyncworldedit.core.queue.IQueueExtent; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.TaskManager; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -import it.unimi.dsi.fastutil.longs.LongArraySet; -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.longs.LongSet; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.TicketType; import net.minecraft.util.Unit; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.chunk.ChunkStatus; -import org.apache.logging.log4j.Logger; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import java.util.function.IntConsumer; -public class PaperweightStarlightRelighter implements Relighter { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - private static final int CHUNKS_PER_BATCH = 1024; // 32 * 32 - private static final int CHUNKS_PER_BATCH_SQRT_LOG2 = 5; // for shifting +public class PaperweightStarlightRelighter extends StarlightRelighter { private static final TicketType FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkStatus.getDistance(ChunkStatus.LIGHT); - - private final ServerLevel serverLevel; - private final ReentrantLock lock = new ReentrantLock(); - private final Long2ObjectLinkedOpenHashMap regions = new Long2ObjectLinkedOpenHashMap<>(); - private final ReentrantLock areaLock = new ReentrantLock(); - private final NMSRelighter delegate; - public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { - this.serverLevel = serverLevel; - this.delegate = new NMSRelighter(queue); + super(serverLevel, queue); } @Override - public boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask) { - areaLock.lock(); - try { - long key = MathMan.pairInt(cx >> CHUNKS_PER_BATCH_SQRT_LOG2, cz >> CHUNKS_PER_BATCH_SQRT_LOG2); - // TODO probably submit here already if chunks.size == CHUNKS_PER_BATCH? - LongSet chunks = this.regions.computeIfAbsent(key, k -> new LongArraySet(CHUNKS_PER_BATCH >> 2)); - chunks.add(ChunkPos.asLong(cx, cz)); - } finally { - areaLock.unlock(); - } - return true; + protected ChunkPos createChunkPos(final long chunkKey) { + return new ChunkPos(chunkKey); } @Override - public void addLightUpdate(int x, int y, int z) { - delegate.addLightUpdate(x, y, z); + protected long asLong(final int chunkX, final int chunkZ) { + return ChunkPos.asLong(chunkX, chunkZ); } - /* - * This method is called "recursively", iterating and removing elements - * from the regions linked map. This way, chunks are loaded in batches to avoid - * OOMEs. - */ @Override - public void fixLightingSafe(boolean sky) { - this.areaLock.lock(); - try { - if (regions.isEmpty()) { - return; - } - LongSet first = regions.removeFirst(); - fixLighting(first, () -> fixLightingSafe(true)); - } finally { - this.areaLock.unlock(); - } + protected CompletableFuture chunkLoadFuture(final ChunkPos chunkPos) { + return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z) + .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( + FAWE_TICKET, + chunkPos, + LIGHT_LEVEL, + Unit.INSTANCE + )); } - /* - * Processes a set of chunks and runs an action afterwards. - * The action is run async, the chunks are partly processed on the main thread - * (as required by the server). - */ - private void fixLighting(LongSet chunks, Runnable andThen) { - // convert from long keys to ChunkPos - Set coords = new HashSet<>(); - LongIterator iterator = chunks.iterator(); - while (iterator.hasNext()) { - coords.add(new ChunkPos(iterator.nextLong())); - } - TaskManager.taskManager().task(() -> { - // trigger chunk load and apply ticket on main thread - List> futures = new ArrayList<>(); - for (ChunkPos pos : coords) { - futures.add(serverLevel.getWorld().getChunkAtAsync(pos.x, pos.z) - .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( - FAWE_TICKET, - pos, - LIGHT_LEVEL, - Unit.INSTANCE - )) - ); - } - // collect futures and trigger relight once all chunks are loaded - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(v -> - invokeRelight( - coords, - c -> { - }, // no callback for single chunks required - i -> { - if (i != coords.size()) { - LOGGER.warn("Processed {} chunks instead of {}", i, coords.size()); - } - // post process chunks on main thread - TaskManager.taskManager().task(() -> postProcessChunks(coords)); - // call callback on our own threads - TaskManager.taskManager().async(andThen); - } - ) - ); - }); - } - - private void invokeRelight( + protected void invokeRelight( Set coords, Consumer chunkCallback, IntConsumer processCallback @@ -148,7 +61,7 @@ public class PaperweightStarlightRelighter implements Relighter { * Allow the server to unload the chunks again. * Also, if chunk packets are sent delayed, we need to do that here */ - private void postProcessChunks(Set coords) { + protected void postProcessChunks(Set coords) { boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING; for (ChunkPos pos : coords) { int x = pos.x; @@ -160,44 +73,4 @@ public class PaperweightStarlightRelighter implements Relighter { } } - @Override - public void clear() { - - } - - @Override - public void removeLighting() { - this.delegate.removeLighting(); - } - - @Override - public void fixBlockLighting() { - fixLightingSafe(true); - } - - @Override - public void fixSkyLighting() { - fixLightingSafe(true); - } - - @Override - public boolean isEmpty() { - return true; - } - - @Override - public ReentrantLock getLock() { - return this.lock; - } - - @Override - public boolean isFinished() { - return false; - } - - @Override - public void close() throws Exception { - fixLightingSafe(true); - } - } diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/StarlightRelighter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/StarlightRelighter.java new file mode 100644 index 000000000..95200054e --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/StarlightRelighter.java @@ -0,0 +1,196 @@ +package com.fastasyncworldedit.bukkit.adapter; + +import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter; +import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; +import com.fastasyncworldedit.core.queue.IQueueExtent; +import com.fastasyncworldedit.core.util.MathMan; +import com.fastasyncworldedit.core.util.TaskManager; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.longs.LongArraySet; +import it.unimi.dsi.fastutil.longs.LongIterator; +import it.unimi.dsi.fastutil.longs.LongSet; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; +import java.util.function.IntConsumer; + +/** + * A base class for version-specific implementations of the starlight relighting mechanism + * + * @param the version-specific ServerLevel type + * @param the version-specific ChunkPos type + * @since TODO + */ +public abstract class StarlightRelighter implements Relighter { + + protected static final Logger LOGGER = LogManagerCompat.getLogger(); + + private static final int CHUNKS_PER_BATCH = 1024; // 32 * 32 + private static final int CHUNKS_PER_BATCH_SQRT_LOG2 = 5; // for shifting + + private final ReentrantLock lock = new ReentrantLock(); + private final Long2ObjectLinkedOpenHashMap regions = new Long2ObjectLinkedOpenHashMap<>(); + private final ReentrantLock areaLock = new ReentrantLock(); + private final NMSRelighter delegate; + protected final SERVER_LEVEL serverLevel; + + protected StarlightRelighter(SERVER_LEVEL serverLevel, IQueueExtent queue) { + this.serverLevel = serverLevel; + this.delegate = new NMSRelighter(queue); + } + + protected Set convertChunkKeysToChunkPos(LongSet chunks) { + // convert from long keys to ChunkPos + Set coords = new HashSet<>(); + LongIterator iterator = chunks.iterator(); + while (iterator.hasNext()) { + coords.add(createChunkPos(iterator.nextLong())); + } + return coords; + } + + protected abstract CHUNK_POS createChunkPos(long chunkKey); + + protected abstract long asLong(int chunkX, int chunkZ); + + protected abstract CompletableFuture chunkLoadFuture(CHUNK_POS pos); + + protected List> chunkLoadFutures(Set coords) { + List> futures = new ArrayList<>(); + for (final CHUNK_POS coord : coords) { + futures.add(chunkLoadFuture(coord)); + } + return futures; + } + + @NotNull + protected IntConsumer postProcessCallback(Runnable andThen, Set coords) { + return i -> { + if (i != coords.size()) { + LOGGER.warn("Processed {} chunks instead of {}", i, coords.size()); + } + // post process chunks on main thread + TaskManager.taskManager().task(() -> postProcessChunks(coords)); + // call callback on our own threads + TaskManager.taskManager().async(andThen); + }; + } + + protected abstract void invokeRelight( + Set coords, + Consumer chunkCallback, + IntConsumer processCallback + ); + + protected abstract void postProcessChunks(Set coords); + + /* + * Processes a set of chunks and runs an action afterwards. + * The action is run async, the chunks are partly processed on the main thread + * (as required by the server). + */ + protected void fixLighting(LongSet chunks, Runnable andThen) { + Set coords = convertChunkKeysToChunkPos(chunks); + TaskManager.taskManager().task(() -> { + // trigger chunk load and apply ticket on main thread + List> futures = chunkLoadFutures(coords); + // collect futures and trigger relight once all chunks are loaded + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(v -> + invokeRelight( + coords, + c -> { + }, // no callback for single chunks required + postProcessCallback(andThen, coords) + ) + ); + }); + } + + @Override + public boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask) { + areaLock.lock(); + try { + long key = MathMan.pairInt(cx >> CHUNKS_PER_BATCH_SQRT_LOG2, cz >> CHUNKS_PER_BATCH_SQRT_LOG2); + // TODO probably submit here already if chunks.size == CHUNKS_PER_BATCH? + LongSet chunks = this.regions.computeIfAbsent(key, k -> new LongArraySet(CHUNKS_PER_BATCH >> 2)); + chunks.add(asLong(cx, cz)); + } finally { + areaLock.unlock(); + } + return true; + } + + /* + * This method is called "recursively", iterating and removing elements + * from the regions linked map. This way, chunks are loaded in batches to avoid + * OOMEs. + */ + + @Override + public void fixLightingSafe(boolean sky) { + this.areaLock.lock(); + try { + if (regions.isEmpty()) { + return; + } + LongSet first = regions.removeFirst(); + fixLighting(first, () -> fixLightingSafe(true)); + } finally { + this.areaLock.unlock(); + } + } + + @Override + public void addLightUpdate(int x, int y, int z) { + this.delegate.addLightUpdate(x, y, z); + } + + @Override + public void clear() { + + } + + @Override + public void removeLighting() { + this.delegate.removeLighting(); + } + + @Override + public void fixBlockLighting() { + fixLightingSafe(true); + } + + @Override + public void fixSkyLighting() { + fixLightingSafe(true); + } + + @Override + public boolean isEmpty() { + return true; + } + + @Override + public ReentrantLock getLock() { + return this.lock; + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public void close() throws Exception { + fixLightingSafe(true); + } + +} From 1f8976b20eb13d3410ec0148dc4212c860e14922 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Tue, 31 Oct 2023 21:23:47 +0100 Subject: [PATCH 058/466] Update Paperweight --- worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts index 041ed296f..2f525f245 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ - the().paperDevBundle("1.20.2-R0.1-20231008.101509-26") + the().paperDevBundle("1.20.2-R0.1-20231029.153906-63") compileOnly(libs.paperlib) } From 462b078c2d1f1e51b14cf6730f50ecb53b1d516f Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Thu, 2 Nov 2023 07:52:30 +0100 Subject: [PATCH 059/466] Support -n (select only) in //place (#2475) --- .../worldedit/command/ClipboardCommands.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index e39bbc641..8ccd4f44e 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 @@ -29,7 +29,6 @@ import com.fastasyncworldedit.core.extent.clipboard.DiskOptimizedClipboard; import com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder; import com.fastasyncworldedit.core.extent.clipboard.ReadOnlyClipboard; import com.fastasyncworldedit.core.extent.clipboard.URIClipboardHolder; -import com.fastasyncworldedit.core.internal.exception.FaweException; import com.fastasyncworldedit.core.internal.io.FastByteArrayOutputStream; import com.fastasyncworldedit.core.limit.FaweLimit; import com.fastasyncworldedit.core.util.ImgurUtility; @@ -449,6 +448,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") @@ -460,10 +461,12 @@ public class ClipboardCommands { final BlockVector3 to = atOrigin ? origin : session.getPlacementPosition(actor); checkPaste(actor, editSession, to, holder, clipboard); - clipboard.paste(editSession, to, !ignoreAirBlocks, pasteEntities, pasteBiomes); + if (!onlySelect) { + clipboard.paste(editSession, to, !ignoreAirBlocks, pasteEntities, pasteBiomes); + } Region region = clipboard.getRegion().clone(); - if (selectPasted) { + if (selectPasted || onlySelect) { BlockVector3 clipboardOffset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin()); BlockVector3 realTo = to.add(holder.getTransform().apply(clipboardOffset.toVector3()).toBlockPoint()); BlockVector3 max = realTo.add(holder @@ -475,7 +478,11 @@ public class ClipboardCommands { selector.learnChanges(); selector.explainRegionAdjust(actor, session); } - actor.print(Caption.of("fawe.worldedit.paste.command.paste", to)); + if (onlySelect) { + actor.print(Caption.of("worldedit.paste.selected")); + } else { + actor.print(Caption.of("fawe.worldedit.paste.command.paste", to)); + } if (!actor.hasPermission("fawe.tips")) { actor.print(Caption.of("fawe.tips.tip.copypaste")); @@ -512,7 +519,7 @@ public class ClipboardCommands { ClipboardHolder holder = session.getClipboard(); //FAWE start - use place if (holder.getTransform().isIdentity() && sourceMask == null) { - place(actor, world, session, editSession, ignoreAirBlocks, atOrigin, selectPasted, + place(actor, world, session, editSession, ignoreAirBlocks, atOrigin, selectPasted, onlySelect, pasteEntities, pasteBiomes ); return; From 41e2c3ddce61d3d702d9497ed3b79c848d146e80 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 2 Nov 2023 07:53:00 +0100 Subject: [PATCH 060/466] Update plotsquared to v7.1.0 (#2480) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1cd38a659..7af861823 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ griefprevention = "16.18.1" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" towny = "0.99.6.0" -plotsquared = "7.0.0" +plotsquared = "7.1.0" # Third party bstats = "3.0.2" From 83d3b393cd7a36da7a296ab9978c1e429f3ba4cf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 2 Nov 2023 07:53:12 +0100 Subject: [PATCH 061/466] Update dependency commons-cli:commons-cli to v1.6.0 (#2479) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7af861823..7bad41f21 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -35,7 +35,7 @@ jlibnoise = "1.0.0" jchronic = "0.2.4a" lz4-java = "1.8.0" lz4-stream = "1.0.0" -commons-cli = "1.5.0" +commons-cli = "1.6.0" paperlib = "1.0.8" paster = "1.1.5" vault = "1.7.1" From 81f6946e7e67d2764f79ca43b418ff57e425ad92 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 2 Nov 2023 07:54:16 +0100 Subject: [PATCH 062/466] Update dependency org.ajoberstar.grgit:grgit-gradle to v5.2.1 (#2476) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index de4d0df68..a65407ce5 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -22,7 +22,7 @@ val properties = Properties().also { props -> dependencies { implementation(gradleApi()) - implementation("org.ajoberstar.grgit:grgit-gradle:5.2.0") + implementation("org.ajoberstar.grgit:grgit-gradle:5.2.1") implementation("com.github.johnrengelman:shadow:8.1.1") implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.5") } From 6c90cc486aea55c4ea36689d14225ca0f1b33892 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 2 Nov 2023 06:55:28 +0000 Subject: [PATCH 063/466] Update dependency org.checkerframework:checker-qual to v3.40.0 (#2481) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7bad41f21..150da48c1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.14.0" adventure-bukkit = "4.3.1" -checkerqual = "3.39.0" +checkerqual = "3.40.0" truezip = "6.8.4" auto-value = "1.10.4" findbugs = "3.0.2" From 8e2691c613261af85e1fbeb6b133da9eae65c424 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 2 Nov 2023 07:04:20 +0000 Subject: [PATCH 064/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.0.1 (#2477) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 150da48c1..397834962 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "16.18.1" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.99.6.0" +towny = "0.100.0.1" plotsquared = "7.1.0" # Third party From 38fc4cf541c4f88bb971e9a38a58d47970ebbb04 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Fri, 3 Nov 2023 15:07:12 +0100 Subject: [PATCH 065/466] Release 2.8.2 --- .../fastasyncworldedit/bukkit/adapter/StarlightRelighter.java | 2 +- .../java/com/fastasyncworldedit/core/queue/IChunkGet.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/StarlightRelighter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/StarlightRelighter.java index 95200054e..02729cfa9 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/StarlightRelighter.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/StarlightRelighter.java @@ -27,7 +27,7 @@ import java.util.function.IntConsumer; * * @param the version-specific ServerLevel type * @param the version-specific ChunkPos type - * @since TODO + * @since 2.8.2 */ public abstract class StarlightRelighter implements Relighter { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java index a3fc6b78a..458b1858c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java @@ -64,14 +64,14 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent, ITileInput { * Lock the {@link IChunkGet#call(IChunkSet, Runnable)} method to the current thread using a reentrant lock. Also locks * related methods e.g. {@link IChunkGet#setCreateCopy(boolean)} * - * @since TODO + * @since 2.8.2 */ default void lockCall() {} /** * Unlock {@link IChunkGet#call(IChunkSet, Runnable)} (and other related methods) to executions from other threads * - * @since TODO + * @since 2.8.2 */ default void unlockCall() {} From e8754bf5808eb073bf4c22c9056cda719d7ae9aa Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Fri, 3 Nov 2023 15:17:09 +0100 Subject: [PATCH 066/466] Release 2.8.2 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index c79bb8083..18b952fcb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s-%s", rootVersion, buildNumber) +version = String.format("%s", rootVersion) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From 1996a38b46012046de17c247ff98627052b28518 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Fri, 3 Nov 2023 15:40:51 +0100 Subject: [PATCH 067/466] Back to snapshot for development --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 18b952fcb..63e05aad2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.8.2") +var rootVersion by extra("2.8.3") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s", rootVersion) +version = String.format("%s-%s", rootVersion, buildNumber) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From 46dd71e8078c860cc27f19663ffe926e2657bdab Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Wed, 8 Nov 2023 21:39:25 +0100 Subject: [PATCH 068/466] Only unlock if previously locked (#2489) --- .../src/main/java/com/sk89q/worldedit/LocalSession.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index ae62a4f73..67bbff7af 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -100,7 +100,6 @@ import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; @@ -406,7 +405,8 @@ public class LocalSession implements TextureHolder { */ public void clearHistory() { //FAWE start - if (Fawe.isMainThread() && !historyWriteLock.tryLock()) { + boolean mainThread = Fawe.isMainThread(); + if (mainThread && !historyWriteLock.tryLock()) { // Do not make main thread wait if we cannot immediately clear history (on player logout usually) TaskManager.taskManager().async(this::clearHistoryTask); return; @@ -414,7 +414,10 @@ public class LocalSession implements TextureHolder { try { clearHistoryTask(); } finally { - historyWriteLock.unlock(); + // only if we are on the main thread, we ever called tryLock -> need to unlock again + if (mainThread) { + historyWriteLock.unlock(); + } } } From 1a7f555add2d101e6abe0d76193b72a7474a2a89 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sat, 18 Nov 2023 15:11:17 +0100 Subject: [PATCH 069/466] Use FastSchematicReader by default (#2478) --- .../sk89q/worldedit/command/SchematicCommands.java | 11 ++++++++--- .../extent/clipboard/io/ClipboardFormats.java | 6 ++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index c677734ef..1158a7847 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 @@ -313,9 +313,9 @@ public class SchematicCommands { Actor actor, LocalSession session, @Arg(desc = "File name.") String filename, - @Arg(desc = "Format name.", def = "fast") - String formatName, //FAWE start - random rotation + @Arg(desc = "Format name.", def = "") + String formatName, @Switch(name = 'r', desc = "Apply random rotation to the clipboard") boolean randomRotate //FAWE end @@ -325,6 +325,11 @@ public class SchematicCommands { //FAWE start ClipboardFormat format; InputStream in = null; + // if format is set explicitly, do not look up by extension! + boolean noExplicitFormat = formatName == null; + if (noExplicitFormat) { + formatName = "fast"; + } try { URI uri; if (formatName.startsWith("url:")) { @@ -369,7 +374,7 @@ public class SchematicCommands { actor.print(Caption.of("fawe.error.no-perm", "worldedit.schematic.load.other")); return; } - if (filename.matches(".*\\.[\\w].*")) { + if (noExplicitFormat && filename.matches(".*\\.[\\w].*")) { format = ClipboardFormats .findByExtension(filename.substring(filename.lastIndexOf('.') + 1)); } else { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java index b00c9ea5b..03cce5d80 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java @@ -26,7 +26,6 @@ import com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder; import com.fastasyncworldedit.core.extent.clipboard.URIClipboardHolder; import com.fastasyncworldedit.core.internal.io.FastByteArrayOutputStream; import com.fastasyncworldedit.core.util.MainUtil; -import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; import com.google.common.io.ByteSource; @@ -51,6 +50,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; @@ -64,7 +64,9 @@ import static com.google.common.base.Preconditions.checkNotNull; public class ClipboardFormats { private static final Map aliasMap = new HashMap<>(); - private static final Multimap fileExtensionMap = HashMultimap.create(); + // FAWE start - keep order of ClipboardFormat entries -> prefer FAST over SPONGE_SCHEMATIC + private static final Multimap fileExtensionMap = Multimaps.newMultimap(new HashMap<>(), LinkedHashSet::new); + // FAWE end private static final List registeredFormats = new ArrayList<>(); public static void registerClipboardFormat(ClipboardFormat format) { From a64d24c6cfecc4bfaf78326be163dc82f6a4fc8f Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sat, 18 Nov 2023 15:02:02 +0000 Subject: [PATCH 070/466] feat: more informative BoundedHeightMask error message --- .../com/sk89q/worldedit/function/mask/BoundedHeightMask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java index 301f2104c..dfe1841d4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java @@ -41,7 +41,7 @@ public class BoundedHeightMask extends AbstractMask { * @param maxY the maximum Y (must be equal to or greater than minY) */ public BoundedHeightMask(int minY, int maxY) { - checkArgument(minY <= maxY, "minY <= maxY required"); + checkArgument(minY <= maxY, "minY <= maxY required. minY:" + minY + " and maxY:" + maxY + " were given."); this.minY = minY; this.maxY = maxY; } From c0a2eef648b3ca6067d41656b41d24895c07d6c0 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Tue, 21 Nov 2023 18:26:11 +0100 Subject: [PATCH 071/466] Reuse generateTree code across versions (#2482) --- .../v1_17_R1_2/PaperweightFaweAdapter.java | 92 ++++++------------- .../fawe/v1_18_R2/PaperweightFaweAdapter.java | 92 ++++++------------- .../fawe/v1_19_R3/PaperweightFaweAdapter.java | 90 ++++++------------ .../fawe/v1_20_R1/PaperweightFaweAdapter.java | 90 ++++++------------ .../fawe/v1_20_R2/PaperweightFaweAdapter.java | 90 ++++++------------ .../bukkit/adapter/FaweAdapter.java | 72 +++++++++++++++ 6 files changed, 214 insertions(+), 312 deletions(-) create mode 100644 worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/FaweAdapter.java diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweAdapter.java index 2029be6f9..ad6e6ae80 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweAdapter.java @@ -1,7 +1,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; -import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; -import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter; +import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; @@ -10,16 +9,13 @@ import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.NbtUtils; -import com.fastasyncworldedit.core.util.TaskManager; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.TileEntityBlock; import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.ext.fawe.PaperweightAdapter; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.nbt.PaperweightLazyCompoundTag; @@ -39,7 +35,6 @@ import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.nbt.BinaryTag; import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; @@ -79,14 +74,12 @@ import net.minecraft.world.level.chunk.LevelChunkSection; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.TreeType; +import org.bukkit.World; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; import org.bukkit.craftbukkit.v1_17_R1.CraftServer; import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlockState; import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; @@ -110,8 +103,7 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements - IDelegateBukkitImplAdapter { +public final class PaperweightFaweAdapter extends FaweAdapter { private static final Logger LOGGER = LogManagerCompat.getLogger(); @@ -235,11 +227,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements public BlockState getBlock(Location location) { Preconditions.checkNotNull(location); - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); int x = location.getBlockX(); int y = location.getBlockY(); int z = location.getBlockZ(); - final ServerLevel handle = craftWorld.getHandle(); + final ServerLevel handle = getServerLevel(location.getWorld()); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); final BlockPos blockPos = new BlockPos(x, y, z); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); @@ -255,12 +246,11 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements public BaseBlock getFullBlock(final Location location) { Preconditions.checkNotNull(location); - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); int x = location.getBlockX(); int y = location.getBlockY(); int z = location.getBlockZ(); - final ServerLevel handle = craftWorld.getHandle(); + final ServerLevel handle = getServerLevel(location.getWorld()); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); final BlockPos blockPos = new BlockPos(x, y, z); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); @@ -344,10 +334,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightFaweWorldNativeAccess( - this, - new WeakReference<>(((CraftWorld) world).getHandle()) - ); + return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); } @Override @@ -492,7 +479,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + ServerLevel nmsWorld = getServerLevel(world); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); if (map != null && map.wasAccessibleSinceLastSave()) { boolean flag = false; @@ -530,7 +517,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements int internalId = BlockStateIdAccess.getBlockStateId(blockState); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); return blockState1.hasPostProcess( - ((CraftWorld) world).getHandle(), + getServerLevel(world), new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) ); } @@ -546,54 +533,33 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements } @Override - public boolean generateTree( - TreeGenerator.TreeType treeType, EditSession editSession, BlockVector3 blockVector3, - org.bukkit.World bukkitWorld - ) { - TreeType bukkitType = BukkitWorld.toBukkitTreeType(treeType); - if (bukkitType == TreeType.CHORUS_PLANT) { - blockVector3 = blockVector3.add( - 0, - 1, - 0 - ); // bukkit skips the feature gen which does this offset normally, so we have to add it back - } - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - final BlockVector3 finalBlockVector = blockVector3; - // Sync to main thread to ensure no clashes occur - Map placed = TaskManager.taskManager().sync(() -> { - serverLevel.captureTreeGeneration = true; - serverLevel.captureBlockStates = true; - try { - if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) { - return null; - } - return ImmutableMap.copyOf(serverLevel.capturedBlockStates); - } finally { - serverLevel.captureBlockStates = false; - serverLevel.captureTreeGeneration = false; - serverLevel.capturedBlockStates.clear(); - } - }); - if (placed == null || placed.isEmpty()) { - return false; - } - for (CraftBlockState craftBlockState : placed.values()) { - if (craftBlockState == null || craftBlockState.getType() == Material.AIR) { - continue; - } - editSession.setBlock(craftBlockState.getX(), craftBlockState.getY(), craftBlockState.getZ(), - BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData()) - ); - } - return true; + protected void preCaptureStates(final ServerLevel serverLevel) { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + } + + @Override + protected List getCapturedBlockStatesCopy(final ServerLevel serverLevel) { + return new ArrayList<>(serverLevel.capturedBlockStates.values()); + } + + @Override + protected void postCaptureBlockStates(final ServerLevel serverLevel) { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + + @Override + protected ServerLevel getServerLevel(final World world) { + return ((CraftWorld) world).getHandle(); } @Override public List getEntities(org.bukkit.World world) { // Quickly add each entity to a list copy. List mcEntities = new ArrayList<>(); - ((CraftWorld) world).getHandle().entityManager.getEntityGetter().getAll().forEach(mcEntities::add); + getServerLevel(world).entityManager.getEntityGetter().getAll().forEach(mcEntities::add); List list = new ArrayList<>(); mcEntities.forEach((mcEnt) -> { diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightFaweAdapter.java index 49125529d..8b96e2ea6 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightFaweAdapter.java @@ -1,7 +1,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; -import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; -import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter; +import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; @@ -10,16 +9,13 @@ import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.NbtUtils; -import com.fastasyncworldedit.core.util.TaskManager; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.TileEntityBlock; import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R2.PaperweightAdapter; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag; @@ -39,7 +35,6 @@ import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.nbt.BinaryTag; import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; @@ -80,14 +75,12 @@ import net.minecraft.world.level.chunk.LevelChunkSection; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.TreeType; +import org.bukkit.World; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_18_R2.CraftChunk; import org.bukkit.craftbukkit.v1_18_R2.CraftServer; import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlockState; import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity; import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; @@ -111,8 +104,7 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements - IDelegateBukkitImplAdapter { +public final class PaperweightFaweAdapter extends FaweAdapter { private static final Logger LOGGER = LogManagerCompat.getLogger(); @@ -235,11 +227,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements public BlockState getBlock(Location location) { Preconditions.checkNotNull(location); - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); int x = location.getBlockX(); int y = location.getBlockY(); int z = location.getBlockZ(); - final ServerLevel handle = craftWorld.getHandle(); + final ServerLevel handle = getServerLevel(location.getWorld()); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); final BlockPos blockPos = new BlockPos(x, y, z); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); @@ -255,12 +246,11 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements public BaseBlock getFullBlock(final Location location) { Preconditions.checkNotNull(location); - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); int x = location.getBlockX(); int y = location.getBlockY(); int z = location.getBlockZ(); - final ServerLevel handle = craftWorld.getHandle(); + final ServerLevel handle = getServerLevel(location.getWorld()); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); final BlockPos blockPos = new BlockPos(x, y, z); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); @@ -337,10 +327,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightFaweWorldNativeAccess( - this, - new WeakReference<>(((CraftWorld) world).getHandle()) - ); + return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); } @Override @@ -485,7 +472,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + ServerLevel nmsWorld = getServerLevel(world); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); if (map != null && map.wasAccessibleSinceLastSave()) { // PlayerChunk.d players = map.players; @@ -522,7 +509,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements int internalId = BlockStateIdAccess.getBlockStateId(blockState); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); return blockState1.hasPostProcess( - ((CraftWorld) world).getHandle(), + getServerLevel(world), new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) ); } @@ -538,54 +525,33 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements } @Override - public boolean generateTree( - TreeGenerator.TreeType treeType, EditSession editSession, BlockVector3 blockVector3, - org.bukkit.World bukkitWorld - ) { - TreeType bukkitType = BukkitWorld.toBukkitTreeType(treeType); - if (bukkitType == TreeType.CHORUS_PLANT) { - blockVector3 = blockVector3.add( - 0, - 1, - 0 - ); // bukkit skips the feature gen which does this offset normally, so we have to add it back - } - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - final BlockVector3 finalBlockVector = blockVector3; - // Sync to main thread to ensure no clashes occur - Map placed = TaskManager.taskManager().sync(() -> { - serverLevel.captureTreeGeneration = true; - serverLevel.captureBlockStates = true; - try { - if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) { - return null; - } - return ImmutableMap.copyOf(serverLevel.capturedBlockStates); - } finally { - serverLevel.captureBlockStates = false; - serverLevel.captureTreeGeneration = false; - serverLevel.capturedBlockStates.clear(); - } - }); - if (placed == null || placed.isEmpty()) { - return false; - } - for (CraftBlockState craftBlockState : placed.values()) { - if (craftBlockState == null || craftBlockState.getType() == Material.AIR) { - continue; - } - editSession.setBlock(craftBlockState.getX(), craftBlockState.getY(), craftBlockState.getZ(), - BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData()) - ); - } - return true; + protected void preCaptureStates(final ServerLevel serverLevel) { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + } + + @Override + protected List getCapturedBlockStatesCopy(final ServerLevel serverLevel) { + return new ArrayList<>(serverLevel.capturedBlockStates.values()); + } + + @Override + protected void postCaptureBlockStates(final ServerLevel serverLevel) { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + + @Override + protected ServerLevel getServerLevel(final World world) { + return ((CraftWorld) world).getHandle(); } @Override public List getEntities(org.bukkit.World world) { // Quickly add each entity to a list copy. List mcEntities = new ArrayList<>(); - ((CraftWorld) world).getHandle().entityManager.getEntityGetter().getAll().forEach(mcEntities::add); + getServerLevel(world).entityManager.getEntityGetter().getAll().forEach(mcEntities::add); List list = new ArrayList<>(); mcEntities.forEach((mcEnt) -> { diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweAdapter.java index 82aba5fb6..82b13843b 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweAdapter.java @@ -1,7 +1,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; -import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; -import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter; +import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; @@ -10,15 +9,12 @@ import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.NbtUtils; -import com.fastasyncworldedit.core.util.TaskManager; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R3.PaperweightAdapter; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt.PaperweightLazyCompoundTag; @@ -38,7 +34,6 @@ import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.nbt.BinaryTag; import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; @@ -77,13 +72,11 @@ import net.minecraft.world.level.chunk.LevelChunk; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.TreeType; +import org.bukkit.World; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_19_R3.CraftServer; import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlockState; import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; @@ -111,8 +104,7 @@ import java.util.stream.Stream; import static net.minecraft.core.registries.Registries.BIOME; -public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements - IDelegateBukkitImplAdapter { +public final class PaperweightFaweAdapter extends FaweAdapter { private static final Logger LOGGER = LogManagerCompat.getLogger(); private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; @@ -244,11 +236,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements public BlockState getBlock(Location location) { Preconditions.checkNotNull(location); - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); int x = location.getBlockX(); int y = location.getBlockY(); int z = location.getBlockZ(); - final ServerLevel handle = craftWorld.getHandle(); + final ServerLevel handle = getServerLevel(location.getWorld()); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); final BlockPos blockPos = new BlockPos(x, y, z); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); @@ -264,12 +255,11 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements public BaseBlock getFullBlock(final Location location) { Preconditions.checkNotNull(location); - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); int x = location.getBlockX(); int y = location.getBlockY(); int z = location.getBlockZ(); - final ServerLevel handle = craftWorld.getHandle(); + final ServerLevel handle = getServerLevel(location.getWorld()); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); final BlockPos blockPos = new BlockPos(x, y, z); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); @@ -298,10 +288,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightFaweWorldNativeAccess( - this, - new WeakReference<>(((CraftWorld) world).getHandle()) - ); + return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); } @Override @@ -446,7 +433,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + ServerLevel nmsWorld = getServerLevel(world); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); if (map != null && wasAccessibleSinceLastSave(map)) { boolean flag = false; @@ -484,7 +471,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements int internalId = BlockStateIdAccess.getBlockStateId(blockState); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); return blockState1.hasPostProcess( - ((CraftWorld) world).getHandle(), + getServerLevel(world), new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) ); } @@ -501,47 +488,26 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements } @Override - public boolean generateTree( - TreeGenerator.TreeType treeType, EditSession editSession, BlockVector3 blockVector3, - org.bukkit.World bukkitWorld - ) { - TreeType bukkitType = BukkitWorld.toBukkitTreeType(treeType); - if (bukkitType == TreeType.CHORUS_PLANT) { - blockVector3 = blockVector3.add( - 0, - 1, - 0 - ); // bukkit skips the feature gen which does this offset normally, so we have to add it back - } - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - final BlockVector3 finalBlockVector = blockVector3; - // Sync to main thread to ensure no clashes occur - Map placed = TaskManager.taskManager().sync(() -> { - serverLevel.captureTreeGeneration = true; - serverLevel.captureBlockStates = true; - try { - if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) { - return null; - } - return ImmutableMap.copyOf(serverLevel.capturedBlockStates); - } finally { - serverLevel.captureBlockStates = false; - serverLevel.captureTreeGeneration = false; - serverLevel.capturedBlockStates.clear(); - } - }); - if (placed == null || placed.isEmpty()) { - return false; - } - for (CraftBlockState craftBlockState : placed.values()) { - if (craftBlockState == null || craftBlockState.getType() == Material.AIR) { - continue; - } - editSession.setBlock(craftBlockState.getX(), craftBlockState.getY(), craftBlockState.getZ(), - BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData()) - ); - } - return true; + protected void preCaptureStates(final ServerLevel serverLevel) { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + } + + @Override + protected List getCapturedBlockStatesCopy(final ServerLevel serverLevel) { + return new ArrayList<>(serverLevel.capturedBlockStates.values()); + } + + @Override + protected void postCaptureBlockStates(final ServerLevel serverLevel) { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + + @Override + protected ServerLevel getServerLevel(final World world) { + return ((CraftWorld) world).getHandle(); } @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweAdapter.java index aad40c611..e13ff700f 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweAdapter.java @@ -1,7 +1,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; -import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; -import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter; +import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; @@ -10,15 +9,12 @@ import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.NbtUtils; -import com.fastasyncworldedit.core.util.TaskManager; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1.PaperweightAdapter; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag; @@ -38,7 +34,6 @@ import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.nbt.BinaryTag; import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; @@ -77,13 +72,11 @@ import net.minecraft.world.level.chunk.LevelChunk; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.TreeType; +import org.bukkit.World; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_20_R1.CraftServer; import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlockState; import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer; @@ -111,8 +104,7 @@ import java.util.stream.Stream; import static net.minecraft.core.registries.Registries.BIOME; -public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements - IDelegateBukkitImplAdapter { +public final class PaperweightFaweAdapter extends FaweAdapter { private static final Logger LOGGER = LogManagerCompat.getLogger(); private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; @@ -244,11 +236,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements public BlockState getBlock(Location location) { Preconditions.checkNotNull(location); - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); int x = location.getBlockX(); int y = location.getBlockY(); int z = location.getBlockZ(); - final ServerLevel handle = craftWorld.getHandle(); + final ServerLevel handle = getServerLevel(location.getWorld()); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); final BlockPos blockPos = new BlockPos(x, y, z); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); @@ -264,12 +255,11 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements public BaseBlock getFullBlock(final Location location) { Preconditions.checkNotNull(location); - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); int x = location.getBlockX(); int y = location.getBlockY(); int z = location.getBlockZ(); - final ServerLevel handle = craftWorld.getHandle(); + final ServerLevel handle = getServerLevel(location.getWorld()); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); final BlockPos blockPos = new BlockPos(x, y, z); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); @@ -298,10 +288,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightFaweWorldNativeAccess( - this, - new WeakReference<>(((CraftWorld) world).getHandle()) - ); + return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); } @Override @@ -446,7 +433,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + ServerLevel nmsWorld = getServerLevel(world); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); if (map != null && wasAccessibleSinceLastSave(map)) { boolean flag = false; @@ -484,7 +471,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements int internalId = BlockStateIdAccess.getBlockStateId(blockState); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); return blockState1.hasPostProcess( - ((CraftWorld) world).getHandle(), + getServerLevel(world), new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) ); } @@ -501,47 +488,26 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements } @Override - public boolean generateTree( - TreeGenerator.TreeType treeType, EditSession editSession, BlockVector3 blockVector3, - org.bukkit.World bukkitWorld - ) { - TreeType bukkitType = BukkitWorld.toBukkitTreeType(treeType); - if (bukkitType == TreeType.CHORUS_PLANT) { - blockVector3 = blockVector3.add( - 0, - 1, - 0 - ); // bukkit skips the feature gen which does this offset normally, so we have to add it back - } - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - final BlockVector3 finalBlockVector = blockVector3; - // Sync to main thread to ensure no clashes occur - Map placed = TaskManager.taskManager().sync(() -> { - serverLevel.captureTreeGeneration = true; - serverLevel.captureBlockStates = true; - try { - if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) { - return null; - } - return ImmutableMap.copyOf(serverLevel.capturedBlockStates); - } finally { - serverLevel.captureBlockStates = false; - serverLevel.captureTreeGeneration = false; - serverLevel.capturedBlockStates.clear(); - } - }); - if (placed == null || placed.isEmpty()) { - return false; - } - for (CraftBlockState craftBlockState : placed.values()) { - if (craftBlockState == null || craftBlockState.getType() == Material.AIR) { - continue; - } - editSession.setBlock(craftBlockState.getX(), craftBlockState.getY(), craftBlockState.getZ(), - BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData()) - ); - } - return true; + protected void preCaptureStates(final ServerLevel serverLevel) { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + } + + @Override + protected List getCapturedBlockStatesCopy(final ServerLevel serverLevel) { + return new ArrayList<>(serverLevel.capturedBlockStates.values()); + } + + @Override + protected void postCaptureBlockStates(final ServerLevel serverLevel) { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + + @Override + protected ServerLevel getServerLevel(final World world) { + return ((CraftWorld) world).getHandle(); } @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java index 48bc935cb..851de9a0b 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java @@ -1,7 +1,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; -import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; -import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter; +import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; @@ -10,15 +9,12 @@ import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.NbtUtils; -import com.fastasyncworldedit.core.util.TaskManager; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.regen.PaperweightRegen; @@ -37,7 +33,6 @@ import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.nbt.BinaryTag; import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; @@ -76,13 +71,11 @@ import net.minecraft.world.level.chunk.LevelChunk; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.TreeType; +import org.bukkit.World; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_20_R2.CraftServer; import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlockState; import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R2.entity.CraftEntity; import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; @@ -110,8 +103,7 @@ import java.util.stream.Stream; import static net.minecraft.core.registries.Registries.BIOME; -public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements - IDelegateBukkitImplAdapter { +public final class PaperweightFaweAdapter extends FaweAdapter { private static final Logger LOGGER = LogManagerCompat.getLogger(); private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; @@ -247,11 +239,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements public BlockState getBlock(Location location) { Preconditions.checkNotNull(location); - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); int x = location.getBlockX(); int y = location.getBlockY(); int z = location.getBlockZ(); - final ServerLevel handle = craftWorld.getHandle(); + final ServerLevel handle = getServerLevel(location.getWorld()); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); final BlockPos blockPos = new BlockPos(x, y, z); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); @@ -267,12 +258,11 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements public BaseBlock getFullBlock(final Location location) { Preconditions.checkNotNull(location); - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); int x = location.getBlockX(); int y = location.getBlockY(); int z = location.getBlockZ(); - final ServerLevel handle = craftWorld.getHandle(); + final ServerLevel handle = getServerLevel(location.getWorld()); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); final BlockPos blockPos = new BlockPos(x, y, z); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); @@ -301,10 +291,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightFaweWorldNativeAccess( - this, - new WeakReference<>(((CraftWorld) world).getHandle()) - ); + return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); } @Override @@ -449,7 +436,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + ServerLevel nmsWorld = getServerLevel(world); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); if (map != null && wasAccessibleSinceLastSave(map)) { boolean flag = false; @@ -487,7 +474,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements int internalId = BlockStateIdAccess.getBlockStateId(blockState); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); return blockState1.hasPostProcess( - ((CraftWorld) world).getHandle(), + getServerLevel(world), new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) ); } @@ -504,47 +491,26 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements } @Override - public boolean generateTree( - TreeGenerator.TreeType treeType, EditSession editSession, BlockVector3 blockVector3, - org.bukkit.World bukkitWorld - ) { - TreeType bukkitType = BukkitWorld.toBukkitTreeType(treeType); - if (bukkitType == TreeType.CHORUS_PLANT) { - blockVector3 = blockVector3.add( - 0, - 1, - 0 - ); // bukkit skips the feature gen which does this offset normally, so we have to add it back - } - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - final BlockVector3 finalBlockVector = blockVector3; - // Sync to main thread to ensure no clashes occur - Map placed = TaskManager.taskManager().sync(() -> { - serverLevel.captureTreeGeneration = true; - serverLevel.captureBlockStates = true; - try { - if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) { - return null; - } - return ImmutableMap.copyOf(serverLevel.capturedBlockStates); - } finally { - serverLevel.captureBlockStates = false; - serverLevel.captureTreeGeneration = false; - serverLevel.capturedBlockStates.clear(); - } - }); - if (placed == null || placed.isEmpty()) { - return false; - } - for (CraftBlockState craftBlockState : placed.values()) { - if (craftBlockState == null || craftBlockState.getType() == Material.AIR) { - continue; - } - editSession.setBlock(craftBlockState.getX(), craftBlockState.getY(), craftBlockState.getZ(), - BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData()) - ); - } - return true; + protected void preCaptureStates(final ServerLevel serverLevel) { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + } + + @Override + protected List getCapturedBlockStatesCopy(final ServerLevel serverLevel) { + return new ArrayList<>(serverLevel.capturedBlockStates.values()); + } + + @Override + protected void postCaptureBlockStates(final ServerLevel serverLevel) { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + + @Override + protected ServerLevel getServerLevel(final World world) { + return ((CraftWorld) world).getHandle(); } @Override diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/FaweAdapter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/FaweAdapter.java new file mode 100644 index 000000000..e116daf17 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/FaweAdapter.java @@ -0,0 +1,72 @@ +package com.fastasyncworldedit.bukkit.adapter; + +import com.fastasyncworldedit.core.util.TaskManager; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.TreeGenerator; +import org.bukkit.Material; +import org.bukkit.TreeType; +import org.bukkit.World; +import org.bukkit.block.BlockState; + +import java.util.List; + +/** + * A base class for version-specific implementations of the BukkitImplAdapter + * + * @param the version-specific NBT tag type + * @param the version-specific ServerLevel type + */ +public abstract class FaweAdapter extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter { + + @Override + public boolean generateTree( + final TreeGenerator.TreeType treeType, + final EditSession editSession, + BlockVector3 blockVector3, + final World world + ) { + TreeType bukkitType = BukkitWorld.toBukkitTreeType(treeType); + if (bukkitType == TreeType.CHORUS_PLANT) { + // bukkit skips the feature gen which does this offset normally, so we have to add it back + blockVector3 = blockVector3.add(BlockVector3.UNIT_Y); + } + BlockVector3 target = blockVector3; + SERVER_LEVEL serverLevel = getServerLevel(world); + List placed = TaskManager.taskManager().sync(() -> { + preCaptureStates(serverLevel); + try { + if (!world.generateTree(BukkitAdapter.adapt(world, target), bukkitType)) { + return null; + } + return getCapturedBlockStatesCopy(serverLevel); + } finally { + postCaptureBlockStates(serverLevel); + } + }); + + if (placed == null || placed.isEmpty()) { + return false; + } + for (BlockState blockState : placed) { + if (blockState == null || blockState.getType() == Material.AIR) { + continue; + } + editSession.setBlock(blockState.getX(), blockState.getY(), blockState.getZ(), + BukkitAdapter.adapt(blockState.getBlockData()) + ); + } + return true; + } + + protected abstract void preCaptureStates(SERVER_LEVEL serverLevel); + + protected abstract List getCapturedBlockStatesCopy(SERVER_LEVEL serverLevel); + + protected abstract void postCaptureBlockStates(SERVER_LEVEL serverLevel); + + protected abstract SERVER_LEVEL getServerLevel(World world); + +} From 6722d73c686c5009d23997f8d06bc8c2b3ad5b3b Mon Sep 17 00:00:00 2001 From: Jordan Date: Sat, 25 Nov 2023 20:32:29 +0000 Subject: [PATCH 072/466] fix: fixed history rollback (#2367) - Also go ahead and clean up other parts of this, with more appropriate operators used - Fixes #2366 --- .../core/database/RollbackDatabase.java | 41 ++++++++------ .../core/history/DiskStorageHistory.java | 55 +++++++++++++++---- .../history/RollbackOptimizedHistory.java | 21 +++++++ .../history/changeset/AbstractChangeSet.java | 14 +++-- .../changeset/FaweStreamChangeSet.java | 12 ++-- .../worldedit/command/HistorySubCommands.java | 17 +++--- .../src/main/resources/lang/strings.json | 3 +- 7 files changed, 112 insertions(+), 51 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java index 3624e34c0..603e8061a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java @@ -159,15 +159,20 @@ public class RollbackDatabase extends AsyncNotifyQueue { Future future = call(() -> { try { int count = 0; - String stmtStr = ascending ? uuid == null ? "SELECT * FROM`" + this.prefix + "edits` WHERE `time`>? AND `x2`>=? AND" + - " `x1`<=? AND `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? ORDER BY `time` , `id`" : - "SELECT * FROM`" + this.prefix + "edits` WHERE `time`>? AND" + - " `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? AND `player`=? ORDER BY `time` ASC, `id` ASC" : - uuid == null ? "SELECT * FROM`" + this.prefix + "edits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? " + - "AND `z1`<=? AND `y2`>=? AND `y1`<=? ORDER BY `time` DESC, `id` DESC" : - "SELECT * FROM`" + this.prefix + "edits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND" + - " `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? AND `player`=? ORDER BY `time` DESC, `id` DESC"; - try (PreparedStatement stmt = connection.prepareStatement(stmtStr)) { + String stmtStr; + if (ascending) { + if (uuid == null) { + stmtStr = "SELECT * FROM`%sedits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND " + + "`y2`>=? AND `y1`<=? ORDER BY `time` , `id`"; + } else { + stmtStr = "SELECT * FROM`%sedits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND " + + "`y2`>=? AND `y1`<=? AND `player`=? ORDER BY `time` ASC, `id` ASC"; + } + } else { + stmtStr = "SELECT * FROM`%sedits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND " + + "`y2`>=? AND `y1`<=? AND `player`=? ORDER BY `time` DESC, `id` DESC"; + } + try (PreparedStatement stmt = connection.prepareStatement(stmtStr.formatted(this.prefix))) { stmt.setInt(1, (int) (minTime / 1000)); stmt.setInt(2, pos1.getBlockX()); stmt.setInt(3, pos2.getBlockX()); @@ -193,20 +198,20 @@ public class RollbackDatabase extends AsyncNotifyQueue { if (delete && uuid != null) { try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + "edits` WHERE `player`=? AND `time`>? AND `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? AND `z1`<=?")) { - stmt.setInt(1, (int) (minTime / 1000)); - stmt.setInt(2, pos1.getBlockX()); - stmt.setInt(3, pos2.getBlockX()); - stmt.setInt(4, pos1.getBlockZ()); - stmt.setInt(5, pos2.getBlockZ()); - // Keep 128 offset for backwards-compatibility - stmt.setInt(6, pos1.getBlockY() - 128); - stmt.setInt(7, pos2.getBlockY() - 128); byte[] uuidBytes = ByteBuffer .allocate(16) .putLong(uuid.getMostSignificantBits()) .putLong(uuid.getLeastSignificantBits()) .array(); - stmt.setBytes(8, uuidBytes); + stmt.setBytes(1, uuidBytes); + stmt.setInt(2, (int) (minTime / 1000)); + stmt.setInt(3, pos1.getBlockX()); + stmt.setInt(4, pos2.getBlockX()); + stmt.setInt(5, pos1.getBlockZ()); + stmt.setInt(6, pos2.getBlockZ()); + // Keep 128 offset for backwards-compatibility + stmt.setInt(7, pos1.getBlockY() - 128); + stmt.setInt(8, pos2.getBlockY() - 128); } } return count; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/DiskStorageHistory.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/DiskStorageHistory.java index 7d0bfe76e..eb2e3da59 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/DiskStorageHistory.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/DiskStorageHistory.java @@ -15,8 +15,10 @@ import com.sk89q.jnbt.NBTOutputStream; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.operation.ChangeSetExecutor; +import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.World; +import org.apache.logging.log4j.Logger; import java.io.File; import java.io.FileInputStream; @@ -35,6 +37,7 @@ import java.util.concurrent.ConcurrentHashMap; */ public class DiskStorageHistory extends FaweStreamChangeSet { + private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Map> NEXT_INDEX = new ConcurrentHashMap<>(); private UUID uuid; @@ -141,9 +144,9 @@ public class DiskStorageHistory extends FaweStreamChangeSet { e.printStackTrace(); return; } - EditSession session = toEditSession(actor, regions); - session.setBlocks(this, ChangeSetExecutor.Type.UNDO); - deleteFiles(); + try (EditSession session = toEditSession(actor, regions)) { + session.setBlocks(this, ChangeSetExecutor.Type.UNDO); + } } public void undo(Actor actor) { @@ -371,9 +374,14 @@ public class DiskStorageHistory extends FaweStreamChangeSet { if (!bdFile.exists()) { return null; } - FaweInputStream is = MainUtil.getCompressedIS(new FileInputStream(bdFile)); - readHeader(is); - return is; + try { + FaweInputStream is = MainUtil.getCompressedIS(new FileInputStream(bdFile)); + readHeader(is); + return is; + } catch (IOException e) { + LOGGER.error("Could not load block history file {}", bdFile); + throw e; + } } @Override @@ -381,7 +389,12 @@ public class DiskStorageHistory extends FaweStreamChangeSet { if (!bioFile.exists()) { return null; } - return MainUtil.getCompressedIS(new FileInputStream(bioFile)); + try { + return MainUtil.getCompressedIS(new FileInputStream(bioFile)); + } catch (IOException e) { + LOGGER.error("Could not load biome history file {}", bdFile); + throw e; + } } @Override @@ -389,7 +402,12 @@ public class DiskStorageHistory extends FaweStreamChangeSet { if (!enttFile.exists()) { return null; } - return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(enttFile))); + try { + return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(enttFile))); + } catch (IOException e) { + LOGGER.error("Could not load entity create history file {}", bdFile); + throw e; + } } @Override @@ -397,7 +415,12 @@ public class DiskStorageHistory extends FaweStreamChangeSet { if (!entfFile.exists()) { return null; } - return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(entfFile))); + try { + return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(entfFile))); + } catch (IOException e) { + LOGGER.error("Could not load entity remove history file {}", bdFile); + throw e; + } } @Override @@ -405,7 +428,12 @@ public class DiskStorageHistory extends FaweStreamChangeSet { if (!nbttFile.exists()) { return null; } - return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(nbttFile))); + try { + return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(nbttFile))); + } catch (IOException e) { + LOGGER.error("Could not load tile create history file {}", bdFile); + throw e; + } } @Override @@ -413,7 +441,12 @@ public class DiskStorageHistory extends FaweStreamChangeSet { if (!nbtfFile.exists()) { return null; } - return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(nbtfFile))); + try { + return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(nbtfFile))); + } catch (IOException e) { + LOGGER.error("Could not load tile remove history file {}", bdFile); + throw e; + } } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/RollbackOptimizedHistory.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/RollbackOptimizedHistory.java index 6e7e4068b..1f01f99de 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/RollbackOptimizedHistory.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/RollbackOptimizedHistory.java @@ -7,6 +7,7 @@ import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BiomeType; import org.apache.logging.log4j.Logger; import java.io.IOException; @@ -125,6 +126,26 @@ public class RollbackOptimizedHistory extends DiskStorageHistory { } } + @Override + public void addBiomeChange(int x, int y, int z, BiomeType from, BiomeType to) { + super.addBiomeChange(x, y, z, from, to); + if (x < minX) { + minX = x; + } else if (x > maxX) { + maxX = x; + } + if (y < minY) { + minY = y; + } else if (y > maxY) { + maxY = y; + } + if (z < minZ) { + minZ = z; + } else if (z > maxZ) { + maxZ = z; + } + } + @Override public void writeHeader(OutputStream os, int x, int y, int z) throws IOException { minX = x; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java index c6a2d9bb0..4bbe1a109 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java @@ -257,12 +257,14 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { } public EditSession toEditSession(Actor actor, Region[] regions) { - EditSessionBuilder builder = WorldEdit.getInstance().newEditSessionBuilder().world(getWorld()).actor(actor). - fastMode(false).checkMemory(false).changeSet(this).limitUnlimited(); - if (regions != null) { - builder.allowedRegions(regions); - } else { - builder.allowedRegionsEverywhere(); + EditSessionBuilder builder = WorldEdit.getInstance().newEditSessionBuilder().world(world) + .checkMemory(false) + .changeSetNull() + .fastMode(false) + .limitUnprocessed(actor) + .actor(actor); + if (!actor.getLimit().RESTRICT_HISTORY_TO_REGIONS) { + builder = builder.allowedRegionsEverywhere(); } EditSession editSession = builder.build(); editSession.setSize(1); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java index c2ae362ae..71232a31c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java @@ -167,7 +167,7 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { @Override public int readX(FaweInputStream in) throws IOException { in.readFully(buffer); - return lx = lx + ((((buffer[1] & 0xFF) + ((MathMan.unpair16x(buffer[3])) << 8)) << 20) >> 20); + return lx = lx + ((((buffer[1] & 0xFF) | ((MathMan.unpair16x(buffer[3])) << 8)) << 20) >> 20); } @Override @@ -177,7 +177,7 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { @Override public int readZ(FaweInputStream in) throws IOException { - return lz = lz + ((((buffer[2] & 0xFF) + ((MathMan.unpair16y(buffer[3])) << 8)) << 20) >> 20); + return lz = lz + ((((buffer[2] & 0xFF) | ((MathMan.unpair16y(buffer[3])) << 8)) << 20) >> 20); } }; } else { @@ -203,17 +203,17 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { @Override public int readX(FaweInputStream is) throws IOException { is.readFully(buffer); - return lx = (lx + (buffer[0] & 0xFF) + (buffer[1] << 8)); + return lx = lx + ((buffer[0] & 0xFF) | (buffer[1] << 8)); } @Override public int readY(FaweInputStream is) throws IOException { - return ly = (ly + (buffer[4] & 0xFF) + (buffer[5] << 8)); + return ly = ly + ((buffer[4] & 0xFF) | (buffer[5]) << 8); } @Override public int readZ(FaweInputStream is) throws IOException { - return lz = (lz + (buffer[2] & 0xFF) + (buffer[3] << 8)); + return lz = lz + ((buffer[2] & 0xFF) | (buffer[3]) << 8); } }; } @@ -353,7 +353,7 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { os.write((byte) (z)); // only need to store biomes in the 4x4x4 chunks so only need one byte for y still (signed byte -128 -> 127) // means -512 -> 508. Add 128 to avoid negative value casting. - os.write((byte) (y + 128)); + os.write((byte) (y + 32)); os.writeVarInt(from.getInternalId()); os.writeVarInt(to.getInternalId()); } catch (IOException e) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java index 6b30e9e7e..08f48b265 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java @@ -13,20 +13,22 @@ import com.fastasyncworldedit.core.util.MainUtil; import com.fastasyncworldedit.core.util.StringMan; import com.google.common.base.Function; import com.google.common.collect.Lists; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.EditSessionBuilder; import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; -import com.sk89q.worldedit.command.util.annotation.AllowedRegion; import com.sk89q.worldedit.command.util.annotation.Confirm; import com.sk89q.worldedit.command.util.annotation.Time; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.function.operation.ChangeSetExecutor; import com.sk89q.worldedit.history.changeset.ChangeSet; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Identifiable; @@ -80,7 +82,6 @@ public class HistorySubCommands { @Confirm public synchronized void rerun( Player player, World world, RollbackDatabase database, - @AllowedRegion Region[] allowedRegions, @ArgFlag(name = 'u', desc = "String user", def = "me") UUID other, @ArgFlag(name = 'r', def = "0", desc = "radius") @@ -90,7 +91,7 @@ public class HistorySubCommands { @Time long timeDiff ) throws WorldEditException { - rollback(player, world, database, allowedRegions, other, radius, timeDiff, true); + rollback(player, world, database, other, radius, timeDiff, true); } @Command( @@ -102,7 +103,6 @@ public class HistorySubCommands { @Confirm public synchronized void rollback( Player player, World world, RollbackDatabase database, - @AllowedRegion Region[] allowedRegions, @ArgFlag(name = 'u', desc = "String user", def = "") UUID other, @ArgFlag(name = 'r', def = "0", desc = "radius") @@ -149,9 +149,9 @@ public class HistorySubCommands { count++; RollbackOptimizedHistory edit = supplier.get(); if (restore) { - edit.redo(player, allowedRegions); + edit.redo(player); } else { - edit.undo(player, allowedRegions); + edit.undo(player); } String path = edit.getWorld().getName() + "/" + finalOther + "-" + edit.getIndex(); player.print(Caption.of("fawe.worldedit.rollback.rollback.element", path)); @@ -201,8 +201,7 @@ public class HistorySubCommands { .at(summary.maxX, world.getMaxY(), summary.maxZ) ); rollback.setTime(historyFile.lastModified()); - RollbackDatabase db = DBHandler.dbHandler() - .getDatabase(world); + RollbackDatabase db = DBHandler.dbHandler().getDatabase(world); db.logEdit(rollback); actor.print(TextComponent.of("Logging: " + historyFile)); } diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index 5e922cdae..d702ead53 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -54,7 +54,8 @@ "fawe.worldedit.brush.brush.source.mask": "Brush source mask set", "fawe.worldedit.brush.brush.transform.disabled": "Brush transform disabled", "fawe.worldedit.brush.brush.transform": "Brush transform set", - "fawe.worldedit.rollback.rollback.element": "Undoing {0}", + "fawe.worldedit.rollback.rollingback.index": "Undoing {0} ...", + "fawe.worldedit.rollback.rollback.element": "{0} undone.", "fawe.worldedit.tool.tool.inspect": "Inspect tool bound to {0}.", "fawe.worldedit.tool.tool.inspect.info": "{0} changed {1} to {2} {3} ago", "fawe.worldedit.tool.tool.inspect.info.footer": "Total: {0} changes", From 53ec728f97be0310ea6d3333f042f8fe2433bd37 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sat, 25 Nov 2023 22:43:22 +0100 Subject: [PATCH 073/466] Update paperweight adapters --- worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts index 2f525f245..70c495b7b 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ - the().paperDevBundle("1.20.2-R0.1-20231029.153906-63") + the().paperDevBundle("1.20.2-R0.1-20231125.095734-103") compileOnly(libs.paperlib) } From d1798b7408aae327c9185dce16fd729e952b0311 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sun, 26 Nov 2023 12:28:47 +0000 Subject: [PATCH 074/466] chore: remove bad range annotations --- .../main/java/com/fastasyncworldedit/core/queue/Filter.java | 5 ++--- .../main/java/com/fastasyncworldedit/core/queue/IChunk.java | 3 --- .../java/com/fastasyncworldedit/core/queue/IChunkCache.java | 4 +--- .../java/com/fastasyncworldedit/core/queue/IQueueExtent.java | 5 ++--- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/Filter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/Filter.java index 19fa1293a..366faa8c5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/Filter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/Filter.java @@ -2,7 +2,6 @@ package com.fastasyncworldedit.core.queue; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; import com.sk89q.worldedit.regions.Region; -import org.jetbrains.annotations.Range; import javax.annotation.Nullable; @@ -18,8 +17,8 @@ public interface Filter { * @param chunkZ the z coordinate in the chunk */ default boolean appliesChunk( - @Range(from = 0, to = 15) int chunkX, - @Range(from = 0, to = 15) int chunkZ + int chunkX, + int chunkZ ) { return true; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunk.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunk.java index 126a5cd13..0acfa4a22 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunk.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunk.java @@ -2,7 +2,6 @@ package com.fastasyncworldedit.core.queue; import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock; import com.sk89q.worldedit.regions.Region; -import org.jetbrains.annotations.Range; import javax.annotation.Nullable; @@ -25,7 +24,6 @@ public interface IChunk extends Trimable, IChunkGet, IChunkSet { * * @return the x coordinate of the chunk */ - @Range(from = 0, to = 15) int getX(); /** @@ -33,7 +31,6 @@ public interface IChunk extends Trimable, IChunkGet, IChunkSet { * * @return the z coordinate of the chunk */ - @Range(from = 0, to = 15) int getZ(); /** diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkCache.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkCache.java index ce2761390..8a704e9cb 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkCache.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkCache.java @@ -1,14 +1,12 @@ package com.fastasyncworldedit.core.queue; -import org.jetbrains.annotations.Range; - /** * IGetBlocks may be cached by the WorldChunkCache so that it can be used between multiple * IQueueExtents - avoids conversion between a palette and raw data on every block get */ public interface IChunkCache extends Trimable { - T get(@Range(from = 0, to = 15) int chunkX, @Range(from = 0, to = 15) int chunkZ); + T get(int chunkX, int chunkZ); @Override default boolean trim(boolean aggressive) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java index 01503ad55..104167d30 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java @@ -7,7 +7,6 @@ import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; -import org.jetbrains.annotations.Range; import javax.annotation.Nullable; import java.io.Flushable; @@ -51,12 +50,12 @@ public interface IQueueExtent extends Flushable, Trimable, ICh * Get the cached get object. This is faster than getting the object using NMS and allows for * wrapping. */ - IChunkGet getCachedGet(@Range(from = 0, to = 15) int chunkX, @Range(from = 0, to = 15) int chunkZ); + IChunkGet getCachedGet(int chunkX, int chunkZ); /** * Get the cached chunk set object. */ - IChunkSet getCachedSet(@Range(from = 0, to = 15) int chunkX, @Range(from = 0, to = 15) int chunkZ); + IChunkSet getCachedSet(int chunkX, int chunkZ); /** * Submit the chunk so that it's changes are applied to the world From b754bc01e25c2e2fdbc9b012b0f264211a800fcb Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 26 Nov 2023 13:35:29 +0100 Subject: [PATCH 075/466] Drop support for 1.16.5 and 1.17 (#2497) Drop support for 1.16.5 --- settings.gradle.kts | 2 +- .../adapters/adapter-legacy/build.gradle.kts | 7 ------- .../resources/fastasyncworldedit-adapters.jar | Bin 434371 -> 0 bytes worldedit-bukkit/build.gradle.kts | 2 +- .../fastasyncworldedit/bukkit/FaweBukkit.java | 8 -------- .../bukkit/util/MinecraftVersion.java | 1 - 6 files changed, 2 insertions(+), 18 deletions(-) delete mode 100644 worldedit-bukkit/adapters/adapter-legacy/build.gradle.kts delete mode 100644 worldedit-bukkit/adapters/adapter-legacy/src/main/resources/fastasyncworldedit-adapters.jar diff --git a/settings.gradle.kts b/settings.gradle.kts index 4c6995e2e..d8b8012cf 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,7 +2,7 @@ rootProject.name = "FastAsyncWorldEdit" include("worldedit-libs") -listOf("legacy", "1_17_1", "1_18_2", "1_19_4", "1_20", "1_20_2").forEach { +listOf("1_17_1", "1_18_2", "1_19_4", "1_20", "1_20_2").forEach { include("worldedit-bukkit:adapters:adapter-$it") } diff --git a/worldedit-bukkit/adapters/adapter-legacy/build.gradle.kts b/worldedit-bukkit/adapters/adapter-legacy/build.gradle.kts deleted file mode 100644 index 822c1f70b..000000000 --- a/worldedit-bukkit/adapters/adapter-legacy/build.gradle.kts +++ /dev/null @@ -1,7 +0,0 @@ -plugins { - base -} - -artifacts { - add("default", file("./src/main/resources/fastasyncworldedit-adapters.jar")) -} diff --git a/worldedit-bukkit/adapters/adapter-legacy/src/main/resources/fastasyncworldedit-adapters.jar b/worldedit-bukkit/adapters/adapter-legacy/src/main/resources/fastasyncworldedit-adapters.jar deleted file mode 100644 index 9000989ef76582a02074889aaf55ad7f3645347d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 434371 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%0AQ1#F?4!9 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 256) with 1.18 world heights. Are you sure?"); } - - if (version.isEqualOrLowerThan(MinecraftVersion.ONE_DOT_SIXTEEN_EOL)) { - LOGGER.warn("You are running Minecraft 1.16.5. This version has been released over two years ago (January 2021)."); - LOGGER.warn("FastAsyncWorldEdit will stop operating on this version in the near future."); - LOGGER.warn("Neither Mojang, nor Spigot or other software vendors support this version anymore." + - "Please update your server to a newer version of Minecraft (1.20+) to continue receiving updates and " + - "support."); - } } @Override diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/MinecraftVersion.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/MinecraftVersion.java index f719d430d..08ee52de6 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/MinecraftVersion.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/MinecraftVersion.java @@ -13,7 +13,6 @@ import java.util.regex.Pattern; public class MinecraftVersion implements Comparable { public static final MinecraftVersion NETHER = new MinecraftVersion(1, 16); - public static final MinecraftVersion ONE_DOT_SIXTEEN_EOL = new MinecraftVersion(1, 16, 5); public static final MinecraftVersion CAVES_17 = new MinecraftVersion(1, 17); public static final MinecraftVersion CAVES_18 = new MinecraftVersion(1, 18); private static MinecraftVersion current = null; From f6aa02fe50c485c747edb3a98cd500cc3ccdee19 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 23:48:16 +0100 Subject: [PATCH 076/466] Update actions/setup-java action to v4 (#2508) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build-pr.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/upload-release-assets.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index 98319f7d2..394cb9f56 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -13,7 +13,7 @@ jobs: - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@v1 - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: temurin cache: gradle diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6cda7331f..571658fb4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,7 @@ jobs: - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@v1 - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: temurin cache: gradle diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a0cd830bd..8dd831550 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -21,7 +21,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: temurin cache: gradle diff --git a/.github/workflows/upload-release-assets.yml b/.github/workflows/upload-release-assets.yml index cb1d0a9d1..8f27396ab 100644 --- a/.github/workflows/upload-release-assets.yml +++ b/.github/workflows/upload-release-assets.yml @@ -11,7 +11,7 @@ jobs: - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@v1 - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: temurin cache: gradle From 980caba97c45ef2e241fd4e96795385154c49299 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 23:48:24 +0100 Subject: [PATCH 077/466] Update dependency org.mockito:mockito-core to v5.8.0 (#2505) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- worldedit-sponge/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 397834962..8af2ec263 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -46,7 +46,7 @@ text = "3.0.4" piston = "0.5.7" # Tests -mockito = "5.6.0" +mockito = "5.8.0" # Gradle plugins pluginyml = "0.6.0" diff --git a/worldedit-sponge/build.gradle.kts b/worldedit-sponge/build.gradle.kts index f1aebbeba..8d3ba1539 100644 --- a/worldedit-sponge/build.gradle.kts +++ b/worldedit-sponge/build.gradle.kts @@ -28,7 +28,7 @@ dependencies { }) api("org.apache.logging.log4j:log4j-api") api("org.bstats:bstats-sponge:1.7") - testImplementation("org.mockito:mockito-core:5.6.0") + testImplementation("org.mockito:mockito-core:5.8.0") } <<<<<<< HEAD From 785ac35fd4c5b842752797f415728c7484426d0d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 23:48:33 +0100 Subject: [PATCH 078/466] Update AButler/upload-release-assets action to v3 (#2507) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/upload-release-assets.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/upload-release-assets.yml b/.github/workflows/upload-release-assets.yml index 8f27396ab..7315f1d6c 100644 --- a/.github/workflows/upload-release-assets.yml +++ b/.github/workflows/upload-release-assets.yml @@ -19,7 +19,7 @@ jobs: - name: Clean Build run: ./gradlew clean build --no-daemon - name: Upload Release Assets - uses: AButler/upload-release-assets@v2.0 + uses: AButler/upload-release-assets@v3.0 with: files: 'worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-*.jar' repo-token: ${{ secrets.GITHUB_TOKEN }} From d7a7803a8535a9ac7138a56f6bf7245f1d0a2c76 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 23:48:43 +0100 Subject: [PATCH 079/466] Update plotsquared to v7.2.0 (#2506) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8af2ec263..b3865b3d9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ griefprevention = "16.18.1" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" towny = "0.100.0.1" -plotsquared = "7.1.0" +plotsquared = "7.2.0" # Third party bstats = "3.0.2" From 2247dca23b0c7d1598fc497cc282816c563a5e90 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 23:49:05 +0100 Subject: [PATCH 080/466] Update dependency gradle to v8.5 (#2504) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.jar | Bin 63721 -> 43462 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7f93135c49b765f8051ef9d0a6055ff8e46073d8..d64cd4917707c1f8861d8cb53dd15194d4248596 100644 GIT binary patch literal 43462 zcma&NWl&^owk(X(xVyW%ySuwf;qI=D6|RlDJ2cR^yEKh!@I- zp9QeisK*rlxC>+~7Dk4IxIRsKBHqdR9b3+fyL=ynHmIDe&|>O*VlvO+%z5;9Z$|DJ zb4dO}-R=MKr^6EKJiOrJdLnCJn>np?~vU-1sSFgPu;pthGwf}bG z(1db%xwr#x)r+`4AGu$j7~u2MpVs3VpLp|mx&;>`0p0vH6kF+D2CY0fVdQOZ@h;A` z{infNyvmFUiu*XG}RNMNwXrbec_*a3N=2zJ|Wh5z* z5rAX$JJR{#zP>KY**>xHTuw?|-Rg|o24V)74HcfVT;WtQHXlE+_4iPE8QE#DUm%x0 zEKr75ur~W%w#-My3Tj`hH6EuEW+8K-^5P62$7Sc5OK+22qj&Pd1;)1#4tKihi=~8C zHiQSst0cpri6%OeaR`PY>HH_;CPaRNty%WTm4{wDK8V6gCZlG@U3$~JQZ;HPvDJcT1V{ z?>H@13MJcCNe#5z+MecYNi@VT5|&UiN1D4ATT+%M+h4c$t;C#UAs3O_q=GxK0}8%8 z8J(_M9bayxN}69ex4dzM_P3oh@ZGREjVvn%%r7=xjkqxJP4kj}5tlf;QosR=%4L5y zWhgejO=vao5oX%mOHbhJ8V+SG&K5dABn6!WiKl{|oPkq(9z8l&Mm%(=qGcFzI=eLu zWc_oCLyf;hVlB@dnwY98?75B20=n$>u3b|NB28H0u-6Rpl((%KWEBOfElVWJx+5yg z#SGqwza7f}$z;n~g%4HDU{;V{gXIhft*q2=4zSezGK~nBgu9-Q*rZ#2f=Q}i2|qOp z!!y4p)4o=LVUNhlkp#JL{tfkhXNbB=Ox>M=n6soptJw-IDI|_$is2w}(XY>a=H52d z3zE$tjPUhWWS+5h=KVH&uqQS=$v3nRs&p$%11b%5qtF}S2#Pc`IiyBIF4%A!;AVoI zXU8-Rpv!DQNcF~(qQnyyMy=-AN~U>#&X1j5BLDP{?K!%h!;hfJI>$mdLSvktEr*89 zdJHvby^$xEX0^l9g$xW-d?J;L0#(`UT~zpL&*cEh$L|HPAu=P8`OQZV!-}l`noSp_ zQ-1$q$R-gDL)?6YaM!=8H=QGW$NT2SeZlb8PKJdc=F-cT@j7Xags+Pr*jPtlHFnf- zh?q<6;)27IdPc^Wdy-mX%2s84C1xZq9Xms+==F4);O`VUASmu3(RlgE#0+#giLh-& zcxm3_e}n4{%|X zJp{G_j+%`j_q5}k{eW&TlP}J2wtZ2^<^E(O)4OQX8FDp6RJq!F{(6eHWSD3=f~(h} zJXCf7=r<16X{pHkm%yzYI_=VDP&9bmI1*)YXZeB}F? z(%QsB5fo*FUZxK$oX~X^69;x~j7ms8xlzpt-T15e9}$4T-pC z6PFg@;B-j|Ywajpe4~bk#S6(fO^|mm1hKOPfA%8-_iGCfICE|=P_~e;Wz6my&)h_~ zkv&_xSAw7AZ%ThYF(4jADW4vg=oEdJGVOs>FqamoL3Np8>?!W#!R-0%2Bg4h?kz5I zKV-rKN2n(vUL%D<4oj@|`eJ>0i#TmYBtYmfla;c!ATW%;xGQ0*TW@PTlGG><@dxUI zg>+3SiGdZ%?5N=8uoLA|$4isK$aJ%i{hECP$bK{J#0W2gQ3YEa zZQ50Stn6hqdfxJ*9#NuSLwKFCUGk@c=(igyVL;;2^wi4o30YXSIb2g_ud$ zgpCr@H0qWtk2hK8Q|&wx)}4+hTYlf;$a4#oUM=V@Cw#!$(nOFFpZ;0lc!qd=c$S}Z zGGI-0jg~S~cgVT=4Vo)b)|4phjStD49*EqC)IPwyeKBLcN;Wu@Aeph;emROAwJ-0< z_#>wVm$)ygH|qyxZaet&(Vf%pVdnvKWJn9`%DAxj3ot;v>S$I}jJ$FLBF*~iZ!ZXE zkvui&p}fI0Y=IDX)mm0@tAd|fEHl~J&K}ZX(Mm3cm1UAuwJ42+AO5@HwYfDH7ipIc zmI;1J;J@+aCNG1M`Btf>YT>~c&3j~Qi@Py5JT6;zjx$cvOQW@3oQ>|}GH?TW-E z1R;q^QFjm5W~7f}c3Ww|awg1BAJ^slEV~Pk`Kd`PS$7;SqJZNj->it4DW2l15}xP6 zoCl$kyEF%yJni0(L!Z&14m!1urXh6Btj_5JYt1{#+H8w?5QI%% zo-$KYWNMJVH?Hh@1n7OSu~QhSswL8x0=$<8QG_zepi_`y_79=nK=_ZP_`Em2UI*tyQoB+r{1QYZCpb?2OrgUw#oRH$?^Tj!Req>XiE#~B|~ z+%HB;=ic+R@px4Ld8mwpY;W^A%8%l8$@B@1m5n`TlKI6bz2mp*^^^1mK$COW$HOfp zUGTz-cN9?BGEp}5A!mDFjaiWa2_J2Iq8qj0mXzk; z66JBKRP{p%wN7XobR0YjhAuW9T1Gw3FDvR5dWJ8ElNYF94eF3ebu+QwKjtvVu4L zI9ip#mQ@4uqVdkl-TUQMb^XBJVLW(-$s;Nq;@5gr4`UfLgF$adIhd?rHOa%D);whv z=;krPp~@I+-Z|r#s3yCH+c1US?dnm+C*)r{m+86sTJusLdNu^sqLrfWed^ndHXH`m zd3#cOe3>w-ga(Dus_^ppG9AC>Iq{y%%CK+Cro_sqLCs{VLuK=dev>OL1dis4(PQ5R zcz)>DjEkfV+MO;~>VUlYF00SgfUo~@(&9$Iy2|G0T9BSP?&T22>K46D zL*~j#yJ?)^*%J3!16f)@Y2Z^kS*BzwfAQ7K96rFRIh>#$*$_Io;z>ux@}G98!fWR@ zGTFxv4r~v)Gsd|pF91*-eaZ3Qw1MH$K^7JhWIdX%o$2kCbvGDXy)a?@8T&1dY4`;L z4Kn+f%SSFWE_rpEpL9bnlmYq`D!6F%di<&Hh=+!VI~j)2mfil03T#jJ_s?}VV0_hp z7T9bWxc>Jm2Z0WMU?`Z$xE74Gu~%s{mW!d4uvKCx@WD+gPUQ zV0vQS(Ig++z=EHN)BR44*EDSWIyT~R4$FcF*VEY*8@l=218Q05D2$|fXKFhRgBIEE zdDFB}1dKkoO^7}{5crKX!p?dZWNz$m>1icsXG2N+((x0OIST9Zo^DW_tytvlwXGpn zs8?pJXjEG;T@qrZi%#h93?FP$!&P4JA(&H61tqQi=opRzNpm zkrG}$^t9&XduK*Qa1?355wd8G2CI6QEh@Ua>AsD;7oRUNLPb76m4HG3K?)wF~IyS3`fXuNM>${?wmB zpVz;?6_(Fiadfd{vUCBM*_kt$+F3J+IojI;9L(gc9n3{sEZyzR9o!_mOwFC#tQ{Q~ zP3-`#uK#tP3Q7~Q;4H|wjZHO8h7e4IuBxl&vz2w~D8)w=Wtg31zpZhz%+kzSzL*dV zwp@{WU4i;hJ7c2f1O;7Mz6qRKeASoIv0_bV=i@NMG*l<#+;INk-^`5w@}Dj~;k=|}qM1vq_P z|GpBGe_IKq|LNy9SJhKOQ$c=5L{Dv|Q_lZl=-ky*BFBJLW9&y_C|!vyM~rQx=!vun z?rZJQB5t}Dctmui5i31C_;_}CEn}_W%>oSXtt>@kE1=JW*4*v4tPp;O6 zmAk{)m!)}34pTWg8{i>($%NQ(Tl;QC@J@FfBoc%Gr&m560^kgSfodAFrIjF}aIw)X zoXZ`@IsMkc8_=w%-7`D6Y4e*CG8k%Ud=GXhsTR50jUnm+R*0A(O3UKFg0`K;qp1bl z7``HN=?39ic_kR|^R^~w-*pa?Vj#7|e9F1iRx{GN2?wK!xR1GW!qa=~pjJb-#u1K8 zeR?Y2i-pt}yJq;SCiVHODIvQJX|ZJaT8nO+(?HXbLefulKKgM^B(UIO1r+S=7;kLJ zcH}1J=Px2jsh3Tec&v8Jcbng8;V-`#*UHt?hB(pmOipKwf3Lz8rG$heEB30Sg*2rx zV<|KN86$soN(I!BwO`1n^^uF2*x&vJ$2d$>+`(romzHP|)K_KkO6Hc>_dwMW-M(#S zK(~SiXT1@fvc#U+?|?PniDRm01)f^#55;nhM|wi?oG>yBsa?~?^xTU|fX-R(sTA+5 zaq}-8Tx7zrOy#3*JLIIVsBmHYLdD}!0NP!+ITW+Thn0)8SS!$@)HXwB3tY!fMxc#1 zMp3H?q3eD?u&Njx4;KQ5G>32+GRp1Ee5qMO0lZjaRRu&{W<&~DoJNGkcYF<5(Ab+J zgO>VhBl{okDPn78<%&e2mR{jwVCz5Og;*Z;;3%VvoGo_;HaGLWYF7q#jDX=Z#Ml`H z858YVV$%J|e<1n`%6Vsvq7GmnAV0wW4$5qQ3uR@1i>tW{xrl|ExywIc?fNgYlA?C5 zh$ezAFb5{rQu6i7BSS5*J-|9DQ{6^BVQ{b*lq`xS@RyrsJN?-t=MTMPY;WYeKBCNg z^2|pN!Q^WPJuuO4!|P@jzt&tY1Y8d%FNK5xK(!@`jO2aEA*4 zkO6b|UVBipci?){-Ke=+1;mGlND8)6+P;8sq}UXw2hn;fc7nM>g}GSMWu&v&fqh

iViYT=fZ(|3Ox^$aWPp4a8h24tD<|8-!aK0lHgL$N7Efw}J zVIB!7=T$U`ao1?upi5V4Et*-lTG0XvExbf!ya{cua==$WJyVG(CmA6Of*8E@DSE%L z`V^$qz&RU$7G5mg;8;=#`@rRG`-uS18$0WPN@!v2d{H2sOqP|!(cQ@ zUHo!d>>yFArLPf1q`uBvY32miqShLT1B@gDL4XoVTK&@owOoD)OIHXrYK-a1d$B{v zF^}8D3Y^g%^cnvScOSJR5QNH+BI%d|;J;wWM3~l>${fb8DNPg)wrf|GBP8p%LNGN# z3EaIiItgwtGgT&iYCFy9-LG}bMI|4LdmmJt@V@% zb6B)1kc=T)(|L@0;wr<>=?r04N;E&ef+7C^`wPWtyQe(*pD1pI_&XHy|0gIGHMekd zF_*M4yi6J&Z4LQj65)S zXwdM{SwUo%3SbPwFsHgqF@V|6afT|R6?&S;lw=8% z3}@9B=#JI3@B*#4s!O))~z zc>2_4Q_#&+5V`GFd?88^;c1i7;Vv_I*qt!_Yx*n=;rj!82rrR2rQ8u5(Ejlo{15P% zs~!{%XJ>FmJ})H^I9bn^Re&38H{xA!0l3^89k(oU;bZWXM@kn$#aoS&Y4l^-WEn-fH39Jb9lA%s*WsKJQl?n9B7_~P z-XM&WL7Z!PcoF6_D>V@$CvUIEy=+Z&0kt{szMk=f1|M+r*a43^$$B^MidrT0J;RI` z(?f!O<8UZkm$_Ny$Hth1J#^4ni+im8M9mr&k|3cIgwvjAgjH z8`N&h25xV#v*d$qBX5jkI|xOhQn!>IYZK7l5#^P4M&twe9&Ey@@GxYMxBZq2e7?`q z$~Szs0!g{2fGcp9PZEt|rdQ6bhAgpcLHPz?f-vB?$dc*!9OL?Q8mn7->bFD2Si60* z!O%y)fCdMSV|lkF9w%x~J*A&srMyYY3{=&$}H zGQ4VG_?$2X(0|vT0{=;W$~icCI{b6W{B!Q8xdGhF|D{25G_5_+%s(46lhvNLkik~R z>nr(&C#5wwOzJZQo9m|U<;&Wk!_#q|V>fsmj1g<6%hB{jGoNUPjgJslld>xmODzGjYc?7JSuA?A_QzjDw5AsRgi@Y|Z0{F{!1=!NES-#*f^s4l0Hu zz468))2IY5dmD9pa*(yT5{EyP^G>@ZWumealS-*WeRcZ}B%gxq{MiJ|RyX-^C1V=0 z@iKdrGi1jTe8Ya^x7yyH$kBNvM4R~`fbPq$BzHum-3Zo8C6=KW@||>zsA8-Y9uV5V z#oq-f5L5}V<&wF4@X@<3^C%ptp6+Ce)~hGl`kwj)bsAjmo_GU^r940Z-|`<)oGnh7 zFF0Tde3>ui?8Yj{sF-Z@)yQd~CGZ*w-6p2U<8}JO-sRsVI5dBji`01W8A&3$?}lxBaC&vn0E$c5tW* zX>5(zzZ=qn&!J~KdsPl;P@bmA-Pr8T*)eh_+Dv5=Ma|XSle6t(k8qcgNyar{*ReQ8 zTXwi=8vr>!3Ywr+BhggHDw8ke==NTQVMCK`$69fhzEFB*4+H9LIvdt-#IbhZvpS}} zO3lz;P?zr0*0$%-Rq_y^k(?I{Mk}h@w}cZpMUp|ucs55bcloL2)($u%mXQw({Wzc~ z;6nu5MkjP)0C(@%6Q_I_vsWrfhl7Zpoxw#WoE~r&GOSCz;_ro6i(^hM>I$8y>`!wW z*U^@?B!MMmb89I}2(hcE4zN2G^kwyWCZp5JG>$Ez7zP~D=J^LMjSM)27_0B_X^C(M z`fFT+%DcKlu?^)FCK>QzSnV%IsXVcUFhFdBP!6~se&xxrIxsvySAWu++IrH;FbcY$ z2DWTvSBRfLwdhr0nMx+URA$j3i7_*6BWv#DXfym?ZRDcX9C?cY9sD3q)uBDR3uWg= z(lUIzB)G$Hr!){>E{s4Dew+tb9kvToZp-1&c?y2wn@Z~(VBhqz`cB;{E4(P3N2*nJ z_>~g@;UF2iG{Kt(<1PyePTKahF8<)pozZ*xH~U-kfoAayCwJViIrnqwqO}7{0pHw$ zs2Kx?s#vQr7XZ264>5RNKSL8|Ty^=PsIx^}QqOOcfpGUU4tRkUc|kc7-!Ae6!+B{o~7nFpm3|G5^=0#Bnm6`V}oSQlrX(u%OWnC zoLPy&Q;1Jui&7ST0~#+}I^&?vcE*t47~Xq#YwvA^6^} z`WkC)$AkNub|t@S!$8CBlwbV~?yp&@9h{D|3z-vJXgzRC5^nYm+PyPcgRzAnEi6Q^gslXYRv4nycsy-SJu?lMps-? zV`U*#WnFsdPLL)Q$AmD|0`UaC4ND07+&UmOu!eHruzV|OUox<+Jl|Mr@6~C`T@P%s zW7sgXLF2SSe9Fl^O(I*{9wsFSYb2l%-;&Pi^dpv!{)C3d0AlNY6!4fgmSgj_wQ*7Am7&$z;Jg&wgR-Ih;lUvWS|KTSg!&s_E9_bXBkZvGiC6bFKDWZxsD$*NZ#_8bl zG1P-#@?OQzED7@jlMJTH@V!6k;W>auvft)}g zhoV{7$q=*;=l{O>Q4a@ ziMjf_u*o^PsO)#BjC%0^h>Xp@;5$p{JSYDt)zbb}s{Kbt!T*I@Pk@X0zds6wsefuU zW$XY%yyRGC94=6mf?x+bbA5CDQ2AgW1T-jVAJbm7K(gp+;v6E0WI#kuACgV$r}6L? zd|Tj?^%^*N&b>Dd{Wr$FS2qI#Ucs1yd4N+RBUQiSZGujH`#I)mG&VKoDh=KKFl4=G z&MagXl6*<)$6P}*Tiebpz5L=oMaPrN+caUXRJ`D?=K9!e0f{@D&cZLKN?iNP@X0aF zE(^pl+;*T5qt?1jRC=5PMgV!XNITRLS_=9{CJExaQj;lt!&pdzpK?8p>%Mb+D z?yO*uSung=-`QQ@yX@Hyd4@CI^r{2oiu`%^bNkz+Nkk!IunjwNC|WcqvX~k=><-I3 zDQdbdb|!v+Iz01$w@aMl!R)koD77Xp;eZwzSl-AT zr@Vu{=xvgfq9akRrrM)}=!=xcs+U1JO}{t(avgz`6RqiiX<|hGG1pmop8k6Q+G_mv zJv|RfDheUp2L3=^C=4aCBMBn0aRCU(DQwX-W(RkRwmLeuJYF<0urcaf(=7)JPg<3P zQs!~G)9CT18o!J4{zX{_e}4eS)U-E)0FAt}wEI(c0%HkxgggW;(1E=>J17_hsH^sP z%lT0LGgbUXHx-K*CI-MCrP66UP0PvGqM$MkeLyqHdbgP|_Cm!7te~b8p+e6sQ_3k| zVcwTh6d83ltdnR>D^)BYQpDKlLk3g0Hdcgz2}%qUs9~~Rie)A-BV1mS&naYai#xcZ z(d{8=-LVpTp}2*y)|gR~;qc7fp26}lPcLZ#=JpYcn3AT9(UIdOyg+d(P5T7D&*P}# zQCYplZO5|7+r19%9e`v^vfSS1sbX1c%=w1;oyruXB%Kl$ACgKQ6=qNWLsc=28xJjg zwvsI5-%SGU|3p>&zXVl^vVtQT3o-#$UT9LI@Npz~6=4!>mc431VRNN8od&Ul^+G_kHC`G=6WVWM z%9eWNyy(FTO|A+@x}Ou3CH)oi;t#7rAxdIXfNFwOj_@Y&TGz6P_sqiB`Q6Lxy|Q{`|fgmRG(k+!#b*M+Z9zFce)f-7;?Km5O=LHV9f9_87; zF7%R2B+$?@sH&&-$@tzaPYkw0;=i|;vWdI|Wl3q_Zu>l;XdIw2FjV=;Mq5t1Q0|f< zs08j54Bp`3RzqE=2enlkZxmX6OF+@|2<)A^RNQpBd6o@OXl+i)zO%D4iGiQNuXd+zIR{_lb96{lc~bxsBveIw6umhShTX+3@ZJ=YHh@ zWY3(d0azg;7oHn>H<>?4@*RQbi>SmM=JrHvIG(~BrvI)#W(EAeO6fS+}mxxcc+X~W6&YVl86W9WFSS}Vz-f9vS?XUDBk)3TcF z8V?$4Q)`uKFq>xT=)Y9mMFVTUk*NIA!0$?RP6Ig0TBmUFrq*Q-Agq~DzxjStQyJ({ zBeZ;o5qUUKg=4Hypm|}>>L=XKsZ!F$yNTDO)jt4H0gdQ5$f|d&bnVCMMXhNh)~mN z@_UV6D7MVlsWz+zM+inZZp&P4fj=tm6fX)SG5H>OsQf_I8c~uGCig$GzuwViK54bcgL;VN|FnyQl>Ed7(@>=8$a_UKIz|V6CeVSd2(P z0Uu>A8A+muM%HLFJQ9UZ5c)BSAv_zH#1f02x?h9C}@pN@6{>UiAp>({Fn(T9Q8B z^`zB;kJ5b`>%dLm+Ol}ty!3;8f1XDSVX0AUe5P#@I+FQ-`$(a;zNgz)4x5hz$Hfbg z!Q(z26wHLXko(1`;(BAOg_wShpX0ixfWq3ponndY+u%1gyX)_h=v1zR#V}#q{au6; z!3K=7fQwnRfg6FXtNQmP>`<;!N137paFS%y?;lb1@BEdbvQHYC{976l`cLqn;b8lp zIDY>~m{gDj(wfnK!lpW6pli)HyLEiUrNc%eXTil|F2s(AY+LW5hkKb>TQ3|Q4S9rr zpDs4uK_co6XPsn_z$LeS{K4jFF`2>U`tbgKdyDne`xmR<@6AA+_hPNKCOR-Zqv;xk zu5!HsBUb^!4uJ7v0RuH-7?l?}b=w5lzzXJ~gZcxRKOovSk@|#V+MuX%Y+=;14i*%{)_gSW9(#4%)AV#3__kac1|qUy!uyP{>?U#5wYNq}y$S9pCc zFc~4mgSC*G~j0u#qqp9 z${>3HV~@->GqEhr_Xwoxq?Hjn#=s2;i~g^&Hn|aDKpA>Oc%HlW(KA1?BXqpxB;Ydx)w;2z^MpjJ(Qi(X!$5RC z*P{~%JGDQqojV>2JbEeCE*OEu!$XJ>bWA9Oa_Hd;y)F%MhBRi*LPcdqR8X`NQ&1L# z5#9L*@qxrx8n}LfeB^J{%-?SU{FCwiWyHp682F+|pa+CQa3ZLzBqN1{)h4d6+vBbV zC#NEbQLC;}me3eeYnOG*nXOJZEU$xLZ1<1Y=7r0(-U0P6-AqwMAM`a(Ed#7vJkn6plb4eI4?2y3yOTGmmDQ!z9`wzbf z_OY#0@5=bnep;MV0X_;;SJJWEf^E6Bd^tVJ9znWx&Ks8t*B>AM@?;D4oWUGc z!H*`6d7Cxo6VuyS4Eye&L1ZRhrRmN6Lr`{NL(wDbif|y&z)JN>Fl5#Wi&mMIr5i;x zBx}3YfF>>8EC(fYnmpu~)CYHuHCyr5*`ECap%t@y=jD>!_%3iiE|LN$mK9>- zHdtpy8fGZtkZF?%TW~29JIAfi2jZT8>OA7=h;8T{{k?c2`nCEx9$r zS+*&vt~2o^^J+}RDG@+9&M^K*z4p{5#IEVbz`1%`m5c2};aGt=V?~vIM}ZdPECDI)47|CWBCfDWUbxBCnmYivQ*0Nu_xb*C>~C9(VjHM zxe<*D<#dQ8TlpMX2c@M<9$w!RP$hpG4cs%AI){jp*Sj|*`m)5(Bw*A0$*i-(CA5#%>a)$+jI2C9r6|(>J8InryENI z$NohnxDUB;wAYDwrb*!N3noBTKPpPN}~09SEL18tkG zxgz(RYU_;DPT{l?Q$+eaZaxnsWCA^ds^0PVRkIM%bOd|G2IEBBiz{&^JtNsODs;5z zICt_Zj8wo^KT$7Bg4H+y!Df#3mbl%%?|EXe!&(Vmac1DJ*y~3+kRKAD=Ovde4^^%~ zw<9av18HLyrf*_>Slp;^i`Uy~`mvBjZ|?Ad63yQa#YK`4+c6;pW4?XIY9G1(Xh9WO8{F-Aju+nS9Vmv=$Ac0ienZ+p9*O%NG zMZKy5?%Z6TAJTE?o5vEr0r>f>hb#2w2U3DL64*au_@P!J!TL`oH2r*{>ffu6|A7tv zL4juf$DZ1MW5ZPsG!5)`k8d8c$J$o;%EIL0va9&GzWvkS%ZsGb#S(?{!UFOZ9<$a| zY|a+5kmD5N&{vRqkgY>aHsBT&`rg|&kezoD)gP0fsNYHsO#TRc_$n6Lf1Z{?+DLziXlHrq4sf(!>O{?Tj;Eh@%)+nRE_2VxbN&&%%caU#JDU%vL3}Cb zsb4AazPI{>8H&d=jUaZDS$-0^AxE@utGs;-Ez_F(qC9T=UZX=>ok2k2 ziTn{K?y~a5reD2A)P${NoI^>JXn>`IeArow(41c-Wm~)wiryEP(OS{YXWi7;%dG9v zI?mwu1MxD{yp_rrk!j^cKM)dc4@p4Ezyo%lRN|XyD}}>v=Xoib0gOcdXrQ^*61HNj z=NP|pd>@yfvr-=m{8$3A8TQGMTE7g=z!%yt`8`Bk-0MMwW~h^++;qyUP!J~ykh1GO z(FZ59xuFR$(WE;F@UUyE@Sp>`aVNjyj=Ty>_Vo}xf`e7`F;j-IgL5`1~-#70$9_=uBMq!2&1l zomRgpD58@)YYfvLtPW}{C5B35R;ZVvB<<#)x%srmc_S=A7F@DW8>QOEGwD6suhwCg z>Pa+YyULhmw%BA*4yjDp|2{!T98~<6Yfd(wo1mQ!KWwq0eg+6)o1>W~f~kL<-S+P@$wx*zeI|1t7z#Sxr5 zt6w+;YblPQNplq4Z#T$GLX#j6yldXAqj>4gAnnWtBICUnA&-dtnlh=t0Ho_vEKwV` z)DlJi#!@nkYV#$!)@>udAU*hF?V`2$Hf=V&6PP_|r#Iv*J$9)pF@X3`k;5})9^o4y z&)~?EjX5yX12O(BsFy-l6}nYeuKkiq`u9145&3Ssg^y{5G3Pse z9w(YVa0)N-fLaBq1`P!_#>SS(8fh_5!f{UrgZ~uEdeMJIz7DzI5!NHHqQtm~#CPij z?=N|J>nPR6_sL7!f4hD_|KH`vf8(Wpnj-(gPWH+ZvID}%?~68SwhPTC3u1_cB`otq z)U?6qo!ZLi5b>*KnYHWW=3F!p%h1;h{L&(Q&{qY6)_qxNfbP6E3yYpW!EO+IW3?@J z);4>g4gnl^8klu7uA>eGF6rIGSynacogr)KUwE_R4E5Xzi*Qir@b-jy55-JPC8c~( zo!W8y9OGZ&`xmc8;=4-U9=h{vCqfCNzYirONmGbRQlR`WWlgnY+1wCXbMz&NT~9*| z6@FrzP!LX&{no2!Ln_3|I==_4`@}V?4a;YZKTdw;vT<+K+z=uWbW(&bXEaWJ^W8Td z-3&1bY^Z*oM<=M}LVt>_j+p=2Iu7pZmbXrhQ_k)ysE9yXKygFNw$5hwDn(M>H+e1&9BM5!|81vd%r%vEm zqxY3?F@fb6O#5UunwgAHR9jp_W2zZ}NGp2%mTW@(hz7$^+a`A?mb8|_G*GNMJ) zjqegXQio=i@AINre&%ofexAr95aop5C+0MZ0m-l=MeO8m3epm7U%vZB8+I+C*iNFM z#T3l`gknX;D$-`2XT^Cg*vrv=RH+P;_dfF++cP?B_msQI4j+lt&rX2)3GaJx%W*Nn zkML%D{z5tpHH=dksQ*gzc|}gzW;lwAbxoR07VNgS*-c3d&8J|;@3t^ zVUz*J*&r7DFRuFVDCJDK8V9NN5hvpgGjwx+5n)qa;YCKe8TKtdnh{I7NU9BCN!0dq zczrBk8pE{{@vJa9ywR@mq*J=v+PG;?fwqlJVhijG!3VmIKs>9T6r7MJpC)m!Tc#>g zMtVsU>wbwFJEfwZ{vB|ZlttNe83)$iz`~#8UJ^r)lJ@HA&G#}W&ZH*;k{=TavpjWE z7hdyLZPf*X%Gm}i`Y{OGeeu^~nB8=`{r#TUrM-`;1cBvEd#d!kPqIgYySYhN-*1;L z^byj%Yi}Gx)Wnkosi337BKs}+5H5dth1JA{Ir-JKN$7zC)*}hqeoD(WfaUDPT>0`- z(6sa0AoIqASwF`>hP}^|)a_j2s^PQn*qVC{Q}htR z5-)duBFXT_V56-+UohKXlq~^6uf!6sA#ttk1o~*QEy_Y-S$gAvq47J9Vtk$5oA$Ct zYhYJ@8{hsC^98${!#Ho?4y5MCa7iGnfz}b9jE~h%EAAv~Qxu)_rAV;^cygV~5r_~?l=B`zObj7S=H=~$W zPtI_m%g$`kL_fVUk9J@>EiBH zOO&jtn~&`hIFMS5S`g8w94R4H40mdNUH4W@@XQk1sr17b{@y|JB*G9z1|CrQjd+GX z6+KyURG3;!*BQrentw{B2R&@2&`2}n(z-2&X7#r!{yg@Soy}cRD~j zj9@UBW+N|4HW4AWapy4wfUI- zZ`gSL6DUlgj*f1hSOGXG0IVH8HxK?o2|3HZ;KW{K+yPAlxtb)NV_2AwJm|E)FRs&& z=c^e7bvUsztY|+f^k7NXs$o1EUq>cR7C0$UKi6IooHWlK_#?IWDkvywnzg&ThWo^? z2O_N{5X39#?eV9l)xI(>@!vSB{DLt*oY!K1R8}_?%+0^C{d9a%N4 zoxHVT1&Lm|uDX%$QrBun5e-F`HJ^T$ zmzv)p@4ZHd_w9!%Hf9UYNvGCw2TTTbrj9pl+T9%-_-}L(tES>Or-}Z4F*{##n3~L~TuxjirGuIY#H7{%$E${?p{Q01 zi6T`n;rbK1yIB9jmQNycD~yZq&mbIsFWHo|ZAChSFPQa<(%d8mGw*V3fh|yFoxOOiWJd(qvVb!Z$b88cg->N=qO*4k~6;R==|9ihg&riu#P~s4Oap9O7f%crSr^rljeIfXDEg>wi)&v*a%7zpz<9w z*r!3q9J|390x`Zk;g$&OeN&ctp)VKRpDSV@kU2Q>jtok($Y-*x8_$2piTxun81@vt z!Vj?COa0fg2RPXMSIo26T=~0d`{oGP*eV+$!0I<(4azk&Vj3SiG=Q!6mX0p$z7I}; z9BJUFgT-K9MQQ-0@Z=^7R<{bn2Fm48endsSs`V7_@%8?Bxkqv>BDoVcj?K#dV#uUP zL1ND~?D-|VGKe3Rw_7-Idpht>H6XRLh*U7epS6byiGvJpr%d}XwfusjH9g;Z98H`x zyde%%5mhGOiL4wljCaWCk-&uE4_OOccb9c!ZaWt4B(wYl!?vyzl%7n~QepN&eFUrw zFIOl9c({``6~QD+43*_tzP{f2x41h(?b43^y6=iwyB)2os5hBE!@YUS5?N_tXd=h( z)WE286Fbd>R4M^P{!G)f;h<3Q>Fipuy+d2q-)!RyTgt;wr$(?9ox3;q+{E*ZQHhOn;lM`cjnu9 zXa48ks-v(~b*;MAI<>YZH(^NV8vjb34beE<_cwKlJoR;k6lJNSP6v}uiyRD?|0w+X@o1ONrH8a$fCxXpf? z?$DL0)7|X}Oc%h^zrMKWc-NS9I0Utu@>*j}b@tJ=ixQSJ={4@854wzW@E>VSL+Y{i z#0b=WpbCZS>kUCO_iQz)LoE>P5LIG-hv9E+oG}DtlIDF>$tJ1aw9^LuhLEHt?BCj& z(O4I8v1s#HUi5A>nIS-JK{v!7dJx)^Yg%XjNmlkWAq2*cv#tHgz`Y(bETc6CuO1VkN^L-L3j_x<4NqYb5rzrLC-7uOv z!5e`GZt%B782C5-fGnn*GhDF$%(qP<74Z}3xx+{$4cYKy2ikxI7B2N+2r07DN;|-T->nU&!=Cm#rZt%O_5c&1Z%nlWq3TKAW0w zQqemZw_ue--2uKQsx+niCUou?HjD`xhEjjQd3%rrBi82crq*~#uA4+>vR<_S{~5ce z-2EIl?~s z1=GVL{NxP1N3%=AOaC}j_Fv=ur&THz zyO!d9kHq|c73kpq`$+t+8Bw7MgeR5~`d7ChYyGCBWSteTB>8WAU(NPYt2Dk`@#+}= zI4SvLlyk#pBgVigEe`?NG*vl7V6m+<}%FwPV=~PvvA)=#ths==DRTDEYh4V5}Cf$z@#;< zyWfLY_5sP$gc3LLl2x+Ii)#b2nhNXJ{R~vk`s5U7Nyu^3yFg&D%Txwj6QezMX`V(x z=C`{76*mNb!qHHs)#GgGZ_7|vkt9izl_&PBrsu@}L`X{95-2jf99K)0=*N)VxBX2q z((vkpP2RneSIiIUEnGb?VqbMb=Zia+rF~+iqslydE34cSLJ&BJW^3knX@M;t*b=EA zNvGzv41Ld_T+WT#XjDB840vovUU^FtN_)G}7v)1lPetgpEK9YS^OWFkPoE{ovj^=@ zO9N$S=G$1ecndT_=5ehth2Lmd1II-PuT~C9`XVePw$y8J#dpZ?Tss<6wtVglm(Ok7 z3?^oi@pPio6l&!z8JY(pJvG=*pI?GIOu}e^EB6QYk$#FJQ%^AIK$I4epJ+9t?KjqA+bkj&PQ*|vLttme+`9G=L% ziadyMw_7-M)hS(3E$QGNCu|o23|%O+VN7;Qggp?PB3K-iSeBa2b}V4_wY`G1Jsfz4 z9|SdB^;|I8E8gWqHKx!vj_@SMY^hLEIbSMCuE?WKq=c2mJK z8LoG-pnY!uhqFv&L?yEuxo{dpMTsmCn)95xanqBrNPTgXP((H$9N${Ow~Is-FBg%h z53;|Y5$MUN)9W2HBe2TD`ct^LHI<(xWrw}$qSoei?}s)&w$;&!14w6B6>Yr6Y8b)S z0r71`WmAvJJ`1h&poLftLUS6Ir zC$bG9!Im_4Zjse)#K=oJM9mHW1{%l8sz$1o?ltdKlLTxWWPB>Vk22czVt|1%^wnN@*!l)}?EgtvhC>vlHm^t+ogpgHI1_$1ox9e;>0!+b(tBrmXRB`PY1vp-R**8N7 zGP|QqI$m(Rdu#=(?!(N}G9QhQ%o!aXE=aN{&wtGP8|_qh+7a_j_sU5|J^)vxq;# zjvzLn%_QPHZZIWu1&mRAj;Sa_97p_lLq_{~j!M9N^1yp3U_SxRqK&JnR%6VI#^E12 z>CdOVI^_9aPK2eZ4h&^{pQs}xsijXgFYRIxJ~N7&BB9jUR1fm!(xl)mvy|3e6-B3j zJn#ajL;bFTYJ2+Q)tDjx=3IklO@Q+FFM}6UJr6km7hj7th9n_&JR7fnqC!hTZoM~T zBeaVFp%)0cbPhejX<8pf5HyRUj2>aXnXBqDJe73~J%P(2C?-RT{c3NjE`)om! zl$uewSgWkE66$Kb34+QZZvRn`fob~Cl9=cRk@Es}KQm=?E~CE%spXaMO6YmrMl%9Q zlA3Q$3|L1QJ4?->UjT&CBd!~ru{Ih^in&JXO=|<6J!&qp zRe*OZ*cj5bHYlz!!~iEKcuE|;U4vN1rk$xq6>bUWD*u(V@8sG^7>kVuo(QL@Ki;yL zWC!FT(q{E8#on>%1iAS0HMZDJg{Z{^!De(vSIq&;1$+b)oRMwA3nc3mdTSG#3uYO_ z>+x;7p4I;uHz?ZB>dA-BKl+t-3IB!jBRgdvAbW!aJ(Q{aT>+iz?91`C-xbe)IBoND z9_Xth{6?(y3rddwY$GD65IT#f3<(0o#`di{sh2gm{dw*#-Vnc3r=4==&PU^hCv$qd zjw;>i&?L*Wq#TxG$mFIUf>eK+170KG;~+o&1;Tom9}}mKo23KwdEM6UonXgc z!6N(@k8q@HPw{O8O!lAyi{rZv|DpgfU{py+j(X_cwpKqcalcqKIr0kM^%Br3SdeD> zHSKV94Yxw;pjzDHo!Q?8^0bb%L|wC;4U^9I#pd5O&eexX+Im{ z?jKnCcsE|H?{uGMqVie_C~w7GX)kYGWAg%-?8|N_1#W-|4F)3YTDC+QSq1s!DnOML3@d`mG%o2YbYd#jww|jD$gotpa)kntakp#K;+yo-_ZF9qrNZw<%#C zuPE@#3RocLgPyiBZ+R_-FJ_$xP!RzWm|aN)S+{$LY9vvN+IW~Kf3TsEIvP+B9Mtm! zpfNNxObWQpLoaO&cJh5>%slZnHl_Q~(-Tfh!DMz(dTWld@LG1VRF`9`DYKhyNv z2pU|UZ$#_yUx_B_|MxUq^glT}O5Xt(Vm4Mr02><%C)@v;vPb@pT$*yzJ4aPc_FZ3z z3}PLoMBIM>q_9U2rl^sGhk1VUJ89=*?7|v`{!Z{6bqFMq(mYiA?%KbsI~JwuqVA9$H5vDE+VocjX+G^%bieqx->s;XWlKcuv(s%y%D5Xbc9+ zc(_2nYS1&^yL*ey664&4`IoOeDIig}y-E~_GS?m;D!xv5-xwz+G`5l6V+}CpeJDi^ z%4ed$qowm88=iYG+(`ld5Uh&>Dgs4uPHSJ^TngXP_V6fPyl~>2bhi20QB%lSd#yYn zO05?KT1z@?^-bqO8Cg`;ft>ilejsw@2%RR7;`$Vs;FmO(Yr3Fp`pHGr@P2hC%QcA|X&N2Dn zYf`MqXdHi%cGR@%y7Rg7?d3?an){s$zA{!H;Ie5exE#c~@NhQUFG8V=SQh%UxUeiV zd7#UcYqD=lk-}sEwlpu&H^T_V0{#G?lZMxL7ih_&{(g)MWBnCZxtXg znr#}>U^6!jA%e}@Gj49LWG@*&t0V>Cxc3?oO7LSG%~)Y5}f7vqUUnQ;STjdDU}P9IF9d9<$;=QaXc zL1^X7>fa^jHBu_}9}J~#-oz3Oq^JmGR#?GO7b9a(=R@fw@}Q{{@`Wy1vIQ#Bw?>@X z-_RGG@wt|%u`XUc%W{J z>iSeiz8C3H7@St3mOr_mU+&bL#Uif;+Xw-aZdNYUpdf>Rvu0i0t6k*}vwU`XNO2he z%miH|1tQ8~ZK!zmL&wa3E;l?!!XzgV#%PMVU!0xrDsNNZUWKlbiOjzH-1Uoxm8E#r`#2Sz;-o&qcqB zC-O_R{QGuynW14@)7&@yw1U}uP(1cov)twxeLus0s|7ayrtT8c#`&2~Fiu2=R;1_4bCaD=*E@cYI>7YSnt)nQc zohw5CsK%m?8Ack)qNx`W0_v$5S}nO|(V|RZKBD+btO?JXe|~^Qqur%@eO~<8-L^9d z=GA3-V14ng9L29~XJ>a5k~xT2152zLhM*@zlp2P5Eu}bywkcqR;ISbas&#T#;HZSf z2m69qTV(V@EkY(1Dk3`}j)JMo%ZVJ*5eB zYOjIisi+igK0#yW*gBGj?@I{~mUOvRFQR^pJbEbzFxTubnrw(Muk%}jI+vXmJ;{Q6 zrSobKD>T%}jV4Ub?L1+MGOD~0Ir%-`iTnWZN^~YPrcP5y3VMAzQ+&en^VzKEb$K!Q z<7Dbg&DNXuow*eD5yMr+#08nF!;%4vGrJI++5HdCFcGLfMW!KS*Oi@=7hFwDG!h2< zPunUEAF+HncQkbfFj&pbzp|MU*~60Z(|Ik%Tn{BXMN!hZOosNIseT?R;A`W?=d?5X zK(FB=9mZusYahp|K-wyb={rOpdn=@;4YI2W0EcbMKyo~-#^?h`BA9~o285%oY zfifCh5Lk$SY@|2A@a!T2V+{^!psQkx4?x0HSV`(w9{l75QxMk!)U52Lbhn{8ol?S) zCKo*7R(z!uk<6*qO=wh!Pul{(qq6g6xW;X68GI_CXp`XwO zxuSgPRAtM8K7}5E#-GM!*ydOOG_{A{)hkCII<|2=ma*71ci_-}VPARm3crFQjLYV! z9zbz82$|l01mv`$WahE2$=fAGWkd^X2kY(J7iz}WGS z@%MyBEO=A?HB9=^?nX`@nh;7;laAjs+fbo!|K^mE!tOB>$2a_O0y-*uaIn8k^6Y zSbuv;5~##*4Y~+y7Z5O*3w4qgI5V^17u*ZeupVGH^nM&$qmAk|anf*>r zWc5CV;-JY-Z@Uq1Irpb^O`L_7AGiqd*YpGUShb==os$uN3yYvb`wm6d=?T*it&pDk zo`vhw)RZX|91^^Wa_ti2zBFyWy4cJu#g)_S6~jT}CC{DJ_kKpT`$oAL%b^!2M;JgT zM3ZNbUB?}kP(*YYvXDIH8^7LUxz5oE%kMhF!rnPqv!GiY0o}NR$OD=ITDo9r%4E>E0Y^R(rS^~XjWyVI6 zMOR5rPXhTp*G*M&X#NTL`Hu*R+u*QNoiOKg4CtNPrjgH>c?Hi4MUG#I917fx**+pJfOo!zFM&*da&G_x)L(`k&TPI*t3e^{crd zX<4I$5nBQ8Ax_lmNRa~E*zS-R0sxkz`|>7q_?*e%7bxqNm3_eRG#1ae3gtV9!fQpY z+!^a38o4ZGy9!J5sylDxZTx$JmG!wg7;>&5H1)>f4dXj;B+@6tMlL=)cLl={jLMxY zbbf1ax3S4>bwB9-$;SN2?+GULu;UA-35;VY*^9Blx)Jwyb$=U!D>HhB&=jSsd^6yw zL)?a|>GxU!W}ocTC(?-%z3!IUhw^uzc`Vz_g>-tv)(XA#JK^)ZnC|l1`@CdX1@|!| z_9gQ)7uOf?cR@KDp97*>6X|;t@Y`k_N@)aH7gY27)COv^P3ya9I{4z~vUjLR9~z1Z z5=G{mVtKH*&$*t0@}-i_v|3B$AHHYale7>E+jP`ClqG%L{u;*ff_h@)al?RuL7tOO z->;I}>%WI{;vbLP3VIQ^iA$4wl6@0sDj|~112Y4OFjMs`13!$JGkp%b&E8QzJw_L5 zOnw9joc0^;O%OpF$Qp)W1HI!$4BaXX84`%@#^dk^hFp^pQ@rx4g(8Xjy#!X%+X5Jd@fs3amGT`}mhq#L97R>OwT5-m|h#yT_-v@(k$q7P*9X~T*3)LTdzP!*B} z+SldbVWrrwQo9wX*%FyK+sRXTa@O?WM^FGWOE?S`R(0P{<6p#f?0NJvnBia?k^fX2 zNQs7K-?EijgHJY}&zsr;qJ<*PCZUd*x|dD=IQPUK_nn)@X4KWtqoJNHkT?ZWL_hF? zS8lp2(q>;RXR|F;1O}EE#}gCrY~#n^O`_I&?&z5~7N;zL0)3Tup`%)oHMK-^r$NT% zbFg|o?b9w(q@)6w5V%si<$!U<#}s#x@0aX-hP>zwS#9*75VXA4K*%gUc>+yzupTDBOKH8WR4V0pM(HrfbQ&eJ79>HdCvE=F z|J>s;;iDLB^3(9}?biKbxf1$lI!*Z%*0&8UUq}wMyPs_hclyQQi4;NUY+x2qy|0J; zhn8;5)4ED1oHwg+VZF|80<4MrL97tGGXc5Sw$wAI#|2*cvQ=jB5+{AjMiDHmhUC*a zlmiZ`LAuAn_}hftXh;`Kq0zblDk8?O-`tnilIh|;3lZp@F_osJUV9`*R29M?7H{Fy z`nfVEIDIWXmU&YW;NjU8)EJpXhxe5t+scf|VXM!^bBlwNh)~7|3?fWwo_~ZFk(22% zTMesYw+LNx3J-_|DM~`v93yXe=jPD{q;li;5PD?Dyk+b? zo21|XpT@)$BM$%F=P9J19Vi&1#{jM3!^Y&fr&_`toi`XB1!n>sbL%U9I5<7!@?t)~ z;&H%z>bAaQ4f$wIzkjH70;<8tpUoxzKrPhn#IQfS%9l5=Iu))^XC<58D!-O z{B+o5R^Z21H0T9JQ5gNJnqh#qH^na|z92=hONIM~@_iuOi|F>jBh-?aA20}Qx~EpDGElELNn~|7WRXRFnw+Wdo`|# zBpU=Cz3z%cUJ0mx_1($X<40XEIYz(`noWeO+x#yb_pwj6)R(__%@_Cf>txOQ74wSJ z0#F3(zWWaR-jMEY$7C*3HJrohc79>MCUu26mfYN)f4M~4gD`}EX4e}A!U}QV8!S47 z6y-U-%+h`1n`*pQuKE%Av0@)+wBZr9mH}@vH@i{v(m-6QK7Ncf17x_D=)32`FOjjo zg|^VPf5c6-!FxN{25dvVh#fog=NNpXz zfB$o+0jbRkHH{!TKhE709f+jI^$3#v1Nmf80w`@7-5$1Iv_`)W^px8P-({xwb;D0y z7LKDAHgX<84?l!I*Dvi2#D@oAE^J|g$3!)x1Ua;_;<@#l1fD}lqU2_tS^6Ht$1Wl} zBESo7o^)9-Tjuz$8YQSGhfs{BQV6zW7dA?0b(Dbt=UnQs&4zHfe_sj{RJ4uS-vQpC zX;Bbsuju4%!o8?&m4UZU@~ZZjeFF6ex2ss5_60_JS_|iNc+R0GIjH1@Z z=rLT9%B|WWgOrR7IiIwr2=T;Ne?30M!@{%Qf8o`!>=s<2CBpCK_TWc(DX51>e^xh8 z&@$^b6CgOd7KXQV&Y4%}_#uN*mbanXq(2=Nj`L7H7*k(6F8s6{FOw@(DzU`4-*77{ zF+dxpv}%mFpYK?>N_2*#Y?oB*qEKB}VoQ@bzm>ptmVS_EC(#}Lxxx730trt0G)#$b zE=wVvtqOct1%*9}U{q<)2?{+0TzZzP0jgf9*)arV)*e!f`|jgT{7_9iS@e)recI#z zbzolURQ+TOzE!ymqvBY7+5NnAbWxvMLsLTwEbFqW=CPyCsmJ}P1^V30|D5E|p3BC5 z)3|qgw@ra7aXb-wsa|l^in~1_fm{7bS9jhVRkYVO#U{qMp z)Wce+|DJ}4<2gp8r0_xfZpMo#{Hl2MfjLcZdRB9(B(A(f;+4s*FxV{1F|4d`*sRNd zp4#@sEY|?^FIJ;tmH{@keZ$P(sLh5IdOk@k^0uB^BWr@pk6mHy$qf&~rI>P*a;h0C{%oA*i!VjWn&D~O#MxN&f@1Po# zKN+ zrGrkSjcr?^R#nGl<#Q722^wbYcgW@{+6CBS<1@%dPA8HC!~a`jTz<`g_l5N1M@9wn9GOAZ>nqNgq!yOCbZ@1z`U_N`Z>}+1HIZxk*5RDc&rd5{3qjRh8QmT$VyS;jK z;AF+r6XnnCp=wQYoG|rT2@8&IvKq*IB_WvS%nt%e{MCFm`&W*#LXc|HrD?nVBo=(8*=Aq?u$sDA_sC_RPDUiQ+wnIJET8vx$&fxkW~kP9qXKt zozR)@xGC!P)CTkjeWvXW5&@2?)qt)jiYWWBU?AUtzAN}{JE1I)dfz~7$;}~BmQF`k zpn11qmObXwRB8&rnEG*#4Xax3XBkKlw(;tb?Np^i+H8m(Wyz9k{~ogba@laiEk;2! zV*QV^6g6(QG%vX5Um#^sT&_e`B1pBW5yVth~xUs#0}nv?~C#l?W+9Lsb_5)!71rirGvY zTIJ$OPOY516Y|_014sNv+Z8cc5t_V=i>lWV=vNu#!58y9Zl&GsMEW#pPYPYGHQ|;vFvd*9eM==$_=vc7xnyz0~ zY}r??$<`wAO?JQk@?RGvkWVJlq2dk9vB(yV^vm{=NVI8dhsX<)O(#nr9YD?I?(VmQ z^r7VfUBn<~p3()8yOBjm$#KWx!5hRW)5Jl7wY@ky9lNM^jaT##8QGVsYeaVywmpv>X|Xj7gWE1Ezai&wVLt3p)k4w~yrskT-!PR!kiyQlaxl(( zXhF%Q9x}1TMt3~u@|#wWm-Vq?ZerK={8@~&@9r5JW}r#45#rWii};t`{5#&3$W)|@ zbAf2yDNe0q}NEUvq_Quq3cTjcw z@H_;$hu&xllCI9CFDLuScEMg|x{S7GdV8<&Mq=ezDnRZAyX-8gv97YTm0bg=d)(>N z+B2FcqvI9>jGtnK%eO%y zoBPkJTk%y`8TLf4)IXPBn`U|9>O~WL2C~C$z~9|0m*YH<-vg2CD^SX#&)B4ngOSG$ zV^wmy_iQk>dfN@Pv(ckfy&#ak@MLC7&Q6Ro#!ezM*VEh`+b3Jt%m(^T&p&WJ2Oqvj zs-4nq0TW6cv~(YI$n0UkfwN}kg3_fp?(ijSV#tR9L0}l2qjc7W?i*q01=St0eZ=4h zyGQbEw`9OEH>NMuIe)hVwYHsGERWOD;JxEiO7cQv%pFCeR+IyhwQ|y@&^24k+|8fD zLiOWFNJ2&vu2&`Jv96_z-Cd5RLgmeY3*4rDOQo?Jm`;I_(+ejsPM03!ly!*Cu}Cco zrQSrEDHNyzT(D5s1rZq!8#?f6@v6dB7a-aWs(Qk>N?UGAo{gytlh$%_IhyL7h?DLXDGx zgxGEBQoCAWo-$LRvM=F5MTle`M})t3vVv;2j0HZY&G z22^iGhV@uaJh(XyyY%} zd4iH_UfdV#T=3n}(Lj^|n;O4|$;xhu*8T3hR1mc_A}fK}jfZ7LX~*n5+`8N2q#rI$ z@<_2VANlYF$vIH$ zl<)+*tIWW78IIINA7Rr7i{<;#^yzxoLNkXL)eSs=%|P>$YQIh+ea_3k z_s7r4%j7%&*NHSl?R4k%1>Z=M9o#zxY!n8sL5>BO-ZP;T3Gut>iLS@U%IBrX6BA3k z)&@q}V8a{X<5B}K5s(c(LQ=%v1ocr`t$EqqY0EqVjr65usa=0bkf|O#ky{j3)WBR(((L^wmyHRzoWuL2~WTC=`yZ zn%VX`L=|Ok0v7?s>IHg?yArBcync5rG#^+u)>a%qjES%dRZoIyA8gQ;StH z1Ao7{<&}6U=5}4v<)1T7t!J_CL%U}CKNs-0xWoTTeqj{5{?Be$L0_tk>M9o8 zo371}S#30rKZFM{`H_(L`EM9DGp+Mifk&IP|C2Zu_)Ghr4Qtpmkm1osCf@%Z$%t+7 zYH$Cr)Ro@3-QDeQJ8m+x6%;?YYT;k6Z0E-?kr>x33`H%*ueBD7Zx~3&HtWn0?2Wt} zTG}*|v?{$ajzt}xPzV%lL1t-URi8*Zn)YljXNGDb>;!905Td|mpa@mHjIH%VIiGx- zd@MqhpYFu4_?y5N4xiHn3vX&|e6r~Xt> zZG`aGq|yTNjv;9E+Txuoa@A(9V7g?1_T5FzRI;!=NP1Kqou1z5?%X~Wwb{trRfd>i z8&y^H)8YnKyA_Fyx>}RNmQIczT?w2J4SNvI{5J&}Wto|8FR(W;Qw#b1G<1%#tmYzQ zQ2mZA-PAdi%RQOhkHy9Ea#TPSw?WxwL@H@cbkZwIq0B!@ns}niALidmn&W?!Vd4Gj zO7FiuV4*6Mr^2xlFSvM;Cp_#r8UaqIzHJQg_z^rEJw&OMm_8NGAY2)rKvki|o1bH~ z$2IbfVeY2L(^*rMRU1lM5Y_sgrDS`Z??nR2lX;zyR=c%UyGb*%TC-Dil?SihkjrQy~TMv6;BMs7P8il`H7DmpVm@rJ;b)hW)BL)GjS154b*xq-NXq2cwE z^;VP7ua2pxvCmxrnqUYQMH%a%nHmwmI33nJM(>4LznvY*k&C0{8f*%?zggpDgkuz&JBx{9mfb@wegEl2v!=}Sq2Gaty0<)UrOT0{MZtZ~j5y&w zXlYa_jY)I_+VA-^#mEox#+G>UgvM!Ac8zI<%JRXM_73Q!#i3O|)lOP*qBeJG#BST0 zqohi)O!|$|2SeJQo(w6w7%*92S})XfnhrH_Z8qe!G5>CglP=nI7JAOW?(Z29;pXJ9 zR9`KzQ=WEhy*)WH>$;7Cdz|>*i>=##0bB)oU0OR>>N<21e4rMCHDemNi2LD>Nc$;& zQRFthpWniC1J6@Zh~iJCoLOxN`oCKD5Q4r%ynwgUKPlIEd#?QViIqovY|czyK8>6B zSP%{2-<;%;1`#0mG^B(8KbtXF;Nf>K#Di72UWE4gQ%(_26Koiad)q$xRL~?pN71ZZ zujaaCx~jXjygw;rI!WB=xrOJO6HJ!!w}7eiivtCg5K|F6$EXa)=xUC za^JXSX98W`7g-tm@uo|BKj39Dl;sg5ta;4qjo^pCh~{-HdLl6qI9Ix6f$+qiZ$}s= zNguKrU;u+T@ko(Vr1>)Q%h$?UKXCY>3se%&;h2osl2D zE4A9bd7_|^njDd)6cI*FupHpE3){4NQ*$k*cOWZ_?CZ>Z4_fl@n(mMnYK62Q1d@+I zr&O))G4hMihgBqRIAJkLdk(p(D~X{-oBUA+If@B}j& zsHbeJ3RzTq96lB7d($h$xTeZ^gP0c{t!Y0c)aQE;$FY2!mACg!GDEMKXFOPI^)nHZ z`aSPJpvV0|bbrzhWWkuPURlDeN%VT8tndV8?d)eN*i4I@u zVKl^6{?}A?P)Fsy?3oi#clf}L18t;TjNI2>eI&(ezDK7RyqFxcv%>?oxUlonv(px) z$vnPzRH`y5A(x!yOIfL0bmgeMQB$H5wenx~!ujQK*nUBW;@Em&6Xv2%s(~H5WcU2R z;%Nw<$tI)a`Ve!>x+qegJnQsN2N7HaKzrFqM>`6R*gvh%O*-%THt zrB$Nk;lE;z{s{r^PPm5qz(&lM{sO*g+W{sK+m3M_z=4=&CC>T`{X}1Vg2PEfSj2x_ zmT*(x;ov%3F?qoEeeM>dUn$a*?SIGyO8m806J1W1o+4HRhc2`9$s6hM#qAm zChQ87b~GEw{ADfs+5}FJ8+|bIlIv(jT$Ap#hSHoXdd9#w<#cA<1Rkq^*EEkknUd4& zoIWIY)sAswy6fSERVm&!SO~#iN$OgOX*{9@_BWFyJTvC%S++ilSfCrO(?u=Dc?CXZ zzCG&0yVR{Z`|ZF0eEApWEo#s9osV>F{uK{QA@BES#&;#KsScf>y zvs?vIbI>VrT<*!;XmQS=bhq%46-aambZ(8KU-wOO2=en~D}MCToB_u;Yz{)1ySrPZ z@=$}EvjTdzTWU7c0ZI6L8=yP+YRD_eMMos}b5vY^S*~VZysrkq<`cK3>>v%uy7jgq z0ilW9KjVDHLv0b<1K_`1IkbTOINs0=m-22c%M~l=^S}%hbli-3?BnNq?b`hx^HX2J zIe6ECljRL0uBWb`%{EA=%!i^4sMcj+U_TaTZRb+~GOk z^ZW!nky0n*Wb*r+Q|9H@ml@Z5gU&W`(z4-j!OzC1wOke`TRAYGZVl$PmQ16{3196( zO*?`--I}Qf(2HIwb2&1FB^!faPA2=sLg(@6P4mN)>Dc3i(B0;@O-y2;lM4akD>@^v z=u>*|!s&9zem70g7zfw9FXl1bpJW(C#5w#uy5!V?Q(U35A~$dR%LDVnq@}kQm13{} zd53q3N(s$Eu{R}k2esbftfjfOITCL;jWa$}(mmm}d(&7JZ6d3%IABCapFFYjdEjdK z&4Edqf$G^MNAtL=uCDRs&Fu@FXRgX{*0<(@c3|PNHa>L%zvxWS={L8%qw`STm+=Rd zA}FLspESSIpE_^41~#5yI2bJ=9`oc;GIL!JuW&7YetZ?0H}$$%8rW@*J37L-~Rsx!)8($nI4 zZhcZ2^=Y+p4YPl%j!nFJA|*M^gc(0o$i3nlphe+~-_m}jVkRN{spFs(o0ajW@f3K{ zDV!#BwL322CET$}Y}^0ixYj2w>&Xh12|R8&yEw|wLDvF!lZ#dOTHM9pK6@Nm-@9Lnng4ZHBgBSrr7KI8YCC9DX5Kg|`HsiwJHg2(7#nS;A{b3tVO?Z% za{m5b3rFV6EpX;=;n#wltDv1LE*|g5pQ+OY&*6qCJZc5oDS6Z6JD#6F)bWxZSF@q% z+1WV;m!lRB!n^PC>RgQCI#D1br_o^#iPk>;K2hB~0^<~)?p}LG%kigm@moD#q3PE+ zA^Qca)(xnqw6x>XFhV6ku9r$E>bWNrVH9fum0?4s?Rn2LG{Vm_+QJHse6xa%nzQ?k zKug4PW~#Gtb;#5+9!QBgyB@q=sk9=$S{4T>wjFICStOM?__fr+Kei1 z3j~xPqW;W@YkiUM;HngG!;>@AITg}vAE`M2Pj9Irl4w1fo4w<|Bu!%rh%a(Ai^Zhi zs92>v5;@Y(Zi#RI*ua*h`d_7;byQSa*v9E{2x$<-_=5Z<7{%)}4XExANcz@rK69T0x3%H<@frW>RA8^swA+^a(FxK| zFl3LD*ImHN=XDUkrRhp6RY5$rQ{bRgSO*(vEHYV)3Mo6Jy3puiLmU&g82p{qr0F?ohmbz)f2r{X2|T2 z$4fdQ=>0BeKbiVM!e-lIIs8wVTuC_m7}y4A_%ikI;Wm5$9j(^Y z(cD%U%k)X>_>9~t8;pGzL6L-fmQO@K; zo&vQzMlgY95;1BSkngY)e{`n0!NfVgf}2mB3t}D9@*N;FQ{HZ3Pb%BK6;5#-O|WI( zb6h@qTLU~AbVW#_6?c!?Dj65Now7*pU{h!1+eCV^KCuPAGs28~3k@ueL5+u|Z-7}t z9|lskE`4B7W8wMs@xJa{#bsCGDFoRSNSnmNYB&U7 zVGKWe%+kFB6kb)e;TyHfqtU6~fRg)f|>=5(N36)0+C z`hv65J<$B}WUc!wFAb^QtY31yNleq4dzmG`1wHTj=c*=hay9iD071Hc?oYoUk|M*_ zU1GihAMBsM@5rUJ(qS?9ZYJ6@{bNqJ`2Mr+5#hKf?doa?F|+^IR!8lq9)wS3tF_9n zW_?hm)G(M+MYb?V9YoX^_mu5h-LP^TL^!Q9Z7|@sO(rg_4+@=PdI)WL(B7`!K^ND- z-uIuVDCVEdH_C@c71YGYT^_Scf_dhB8Z2Xy6vGtBSlYud9vggOqv^L~F{BraSE_t} zIkP+Hp2&nH^-MNEs}^`oMLy11`PQW$T|K(`Bu*(f@)mv1-qY(_YG&J2M2<7k;;RK~ zL{Fqj9yCz8(S{}@c)S!65aF<=&eLI{hAMErCx&>i7OeDN>okvegO87OaG{Jmi<|}D zaT@b|0X{d@OIJ7zvT>r+eTzgLq~|Dpu)Z&db-P4z*`M$UL51lf>FLlq6rfG)%doyp z)3kk_YIM!03eQ8Vu_2fg{+osaEJPtJ-s36R+5_AEG12`NG)IQ#TF9c@$99%0iye+ zUzZ57=m2)$D(5Nx!n)=5Au&O0BBgwxIBaeI(mro$#&UGCr<;C{UjJVAbVi%|+WP(a zL$U@TYCxJ=1{Z~}rnW;7UVb7+ZnzgmrogDxhjLGo>c~MiJAWs&&;AGg@%U?Y^0JhL ze(x6Z74JG6FlOFK(T}SXQfhr}RIFl@QXKnIcXYF)5|V~e-}suHILKT-k|<*~Ij|VF zC;t@=uj=hot~*!C68G8hTA%8SzOfETOXQ|3FSaIEjvBJp(A)7SWUi5!Eu#yWgY+;n zlm<$+UDou*V+246_o#V4kMdto8hF%%Lki#zPh}KYXmMf?hrN0;>Mv%`@{0Qn`Ujp) z=lZe+13>^Q!9zT);H<(#bIeRWz%#*}sgUX9P|9($kexOyKIOc`dLux}c$7It4u|Rl z6SSkY*V~g_B-hMPo_ak>>z@AVQ(_N)VY2kB3IZ0G(iDUYw+2d7W^~(Jq}KY=JnWS( z#rzEa&0uNhJ>QE8iiyz;n2H|SV#Og+wEZv=f2%1ELX!SX-(d3tEj$5$1}70Mp<&eI zCkfbByL7af=qQE@5vDVxx1}FSGt_a1DoE3SDI+G)mBAna)KBG4p8Epxl9QZ4BfdAN zFnF|Y(umr;gRgG6NLQ$?ZWgllEeeq~z^ZS7L?<(~O&$5|y)Al^iMKy}&W+eMm1W z7EMU)u^ke(A1#XCV>CZ71}P}0x)4wtHO8#JRG3MA-6g=`ZM!FcICCZ{IEw8Dm2&LQ z1|r)BUG^0GzI6f946RrBlfB1Vs)~8toZf~7)+G;pv&XiUO(%5bm)pl=p>nV^o*;&T z;}@oZSibzto$arQgfkp|z4Z($P>dTXE{4O=vY0!)kDO* zGF8a4wq#VaFpLfK!iELy@?-SeRrdz%F*}hjKcA*y@mj~VD3!it9lhRhX}5YOaR9$} z3mS%$2Be7{l(+MVx3 z(4?h;P!jnRmX9J9sYN#7i=iyj_5q7n#X(!cdqI2lnr8T$IfOW<_v`eB!d9xY1P=2q&WtOXY=D9QYteP)De?S4}FK6#6Ma z=E*V+#s8>L;8aVroK^6iKo=MH{4yEZ_>N-N z`(|;aOATba1^asjxlILk<4}f~`39dBFlxj>Dw(hMYKPO3EEt1@S`1lxFNM+J@uB7T zZ8WKjz7HF1-5&2=l=fqF-*@>n5J}jIxdDwpT?oKM3s8Nr`x8JnN-kCE?~aM1H!hAE z%%w(3kHfGwMnMmNj(SU(w42OrC-euI>Dsjk&jz3ts}WHqmMpzQ3vZrsXrZ|}+MHA7 z068obeXZTsO*6RS@o3x80E4ok``rV^Y3hr&C1;|ZZ0|*EKO`$lECUYG2gVFtUTw)R z4Um<0ZzlON`zTdvVdL#KFoMFQX*a5wM0Czp%wTtfK4Sjs)P**RW&?lP$(<}q%r68Z zS53Y!d@&~ne9O)A^tNrXHhXBkj~$8j%pT1%%mypa9AW5E&s9)rjF4@O3ytH{0z6riz|@< zB~UPh*wRFg2^7EbQrHf0y?E~dHlkOxof_a?M{LqQ^C!i2dawHTPYUE=X@2(3<=OOxs8qn_(y>pU>u^}3y&df{JarR0@VJn0f+U%UiF=$Wyq zQvnVHESil@d|8&R<%}uidGh7@u^(%?$#|&J$pvFC-n8&A>utA=n3#)yMkz+qnG3wd zP7xCnF|$9Dif@N~L)Vde3hW8W!UY0BgT2v(wzp;tlLmyk2%N|0jfG$%<;A&IVrOI< z!L)o>j>;dFaqA3pL}b-Je(bB@VJ4%!JeX@3x!i{yIeIso^=n?fDX`3bU=eG7sTc%g%ye8$v8P@yKE^XD=NYxTb zbf!Mk=h|otpqjFaA-vs5YOF-*GwWPc7VbaOW&stlANnCN8iftFMMrUdYNJ_Bnn5Vt zxfz@Ah|+4&P;reZxp;MmEI7C|FOv8NKUm8njF7Wb6Gi7DeODLl&G~}G4be&*Hi0Qw z5}77vL0P+7-B%UL@3n1&JPxW^d@vVwp?u#gVcJqY9#@-3X{ok#UfW3<1fb%FT`|)V~ggq z(3AUoUS-;7)^hCjdT0Kf{i}h)mBg4qhtHHBti=~h^n^OTH5U*XMgDLIR@sre`AaB$ zg)IGBET_4??m@cx&c~bA80O7B8CHR7(LX7%HThkeC*@vi{-pL%e)yXp!B2InafbDF zjPXf1mko3h59{lT6EEbxKO1Z5GF71)WwowO6kY|6tjSVSWdQ}NsK2x{>i|MKZK8%Q zfu&_0D;CO-Jg0#YmyfctyJ!mRJp)e#@O0mYdp|8x;G1%OZQ3Q847YWTyy|%^cpA;m zze0(5p{tMu^lDkpe?HynyO?a1$_LJl2L&mpeKu%8YvgRNr=%2z${%WThHG=vrWY@4 zsA`OP#O&)TetZ>s%h!=+CE15lOOls&nvC~$Qz0Ph7tHiP;O$i|eDwpT{cp>+)0-|; zY$|bB+Gbel>5aRN3>c0x)4U=|X+z+{ zn*_p*EQoquRL+=+p;=lm`d71&1NqBz&_ph)MXu(Nv6&XE7(RsS)^MGj5Q?Fwude-(sq zjJ>aOq!7!EN>@(fK7EE#;i_BGvli`5U;r!YA{JRodLBc6-`n8K+Fjgwb%sX;j=qHQ z7&Tr!)!{HXoO<2BQrV9Sw?JRaLXV8HrsNevvnf>Y-6|{T!pYLl7jp$-nEE z#X!4G4L#K0qG_4Z;Cj6=;b|Be$hi4JvMH!-voxqx^@8cXp`B??eFBz2lLD8RRaRGh zn7kUfy!YV~p(R|p7iC1Rdgt$_24i0cd-S8HpG|`@my70g^y`gu%#Tf_L21-k?sRRZHK&at(*ED0P8iw{7?R$9~OF$Ko;Iu5)ur5<->x!m93Eb zFYpIx60s=Wxxw=`$aS-O&dCO_9?b1yKiPCQmSQb>T)963`*U+Ydj5kI(B(B?HNP8r z*bfSBpSu)w(Z3j7HQoRjUG(+d=IaE~tv}y14zHHs|0UcN52fT8V_<@2ep_ee{QgZG zmgp8iv4V{k;~8@I%M3<#B;2R>Ef(Gg_cQM7%}0s*^)SK6!Ym+~P^58*wnwV1BW@eG z4sZLqsUvBbFsr#8u7S1r4teQ;t)Y@jnn_m5jS$CsW1um!p&PqAcc8!zyiXHVta9QC zY~wCwCF0U%xiQPD_INKtTb;A|Zf29(mu9NI;E zc-e>*1%(LSXB`g}kd`#}O;veb<(sk~RWL|f3ljxCnEZDdNSTDV6#Td({6l&y4IjKF z^}lIUq*ZUqgTPumD)RrCN{M^jhY>E~1pn|KOZ5((%F)G|*ZQ|r4zIbrEiV%42hJV8 z3xS)=!X1+=olbdGJ=yZil?oXLct8FM{(6ikLL3E%=q#O6(H$p~gQu6T8N!plf!96| z&Q3=`L~>U0zZh;z(pGR2^S^{#PrPxTRHD1RQOON&f)Siaf`GLj#UOk&(|@0?zm;Sx ztsGt8=29-MZs5CSf1l1jNFtNt5rFNZxJPvkNu~2}7*9468TWm>nN9TP&^!;J{-h)_ z7WsHH9|F%I`Pb!>KAS3jQWKfGivTVkMJLO-HUGM_a4UQ_%RgL6WZvrW+Z4ujZn;y@ zz9$=oO!7qVTaQAA^BhX&ZxS*|5dj803M=k&2%QrXda`-Q#IoZL6E(g+tN!6CA!CP* zCpWtCujIea)ENl0liwVfj)Nc<9mV%+e@=d`haoZ*`B7+PNjEbXBkv=B+Pi^~L#EO$D$ZqTiD8f<5$eyb54-(=3 zh)6i8i|jp(@OnRrY5B8t|LFXFQVQ895n*P16cEKTrT*~yLH6Z4e*bZ5otpRDri&+A zfNbK1D5@O=sm`fN=WzWyse!za5n%^+6dHPGX#8DyIK>?9qyX}2XvBWVqbP%%D)7$= z=#$WulZlZR<{m#gU7lwqK4WS1Ne$#_P{b17qe$~UOXCl>5b|6WVh;5vVnR<%d+Lnp z$uEmML38}U4vaW8>shm6CzB(Wei3s#NAWE3)a2)z@i{4jTn;;aQS)O@l{rUM`J@K& l00vQ5JBs~;vo!vr%%-k{2_Fq1Mn4QF81S)AQ99zk{{c4yR+0b! literal 63721 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鯊%1Et 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⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3fa8f862f..1af9e0930 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From af1f22e8fe3f410bf11eabc2cb694f0abd1ac37b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 23:49:48 +0100 Subject: [PATCH 081/466] Update plugin xyz.jpenilla.run-paper to v2.2.2 (#2503) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 63e05aad2..02df265c0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,7 +7,7 @@ import xyz.jpenilla.runpaper.task.RunServer plugins { id("io.github.gradle-nexus.publish-plugin") version "1.3.0" - id("xyz.jpenilla.run-paper") version "2.2.0" + id("xyz.jpenilla.run-paper") version "2.2.2" } if (!File("$rootDir/.git").exists()) { From 11069ee34b8d7932b8d87aa59b7b8fd4ef736950 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 23:50:05 +0100 Subject: [PATCH 082/466] Update dependency com.modrinth.minotaur to v2.8.6 (#2501) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b3865b3d9..6c922efa0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -50,7 +50,7 @@ mockito = "5.8.0" # Gradle plugins pluginyml = "0.6.0" -minotaur = "2.8.4" +minotaur = "2.8.6" [libraries] # Minecraft expectations From 769d8b3a7a660bf471eea00f26013fe1f41663e3 Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 7 Dec 2023 17:24:05 +0000 Subject: [PATCH 083/466] fix: set biome biome on clear (#2510) * fix: set biome biome on clear - fixes #2509 * Nicer biome setting method --- .../bukkit/regions/plotsquared/FaweDelegateRegionManager.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateRegionManager.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateRegionManager.java index 4ef1a3d05..65f8863f8 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateRegionManager.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateRegionManager.java @@ -160,6 +160,10 @@ public class FaweDelegateRegionManager { ); editSession.setBlocks(onTop, air); } + + FlatRegionFunction replace = new BiomeReplace(editSession, biome); + FlatRegionVisitor visitor = new FlatRegionVisitor((CuboidRegion) floorRegion, replace, editSession); + Operations.completeLegacy(visitor); } if (hybridPlotWorld.PLOT_SCHEMATIC) { From d5c8b08fe90f968c921a20472a71238b0c70d36f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 7 Dec 2023 18:24:20 +0100 Subject: [PATCH 084/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.0.8 (#2502) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6c922efa0..5ac2c2ab9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "16.18.1" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.0.1" +towny = "0.100.0.8" plotsquared = "7.2.0" # Third party From ea6138ce1f1bd53113cb900d1e1686ccc610a961 Mon Sep 17 00:00:00 2001 From: RedstoneFuture Date: Thu, 7 Dec 2023 18:26:21 +0100 Subject: [PATCH 085/466] Unify the limit permission (#2420) --- worldedit-bukkit/src/main/resources/plugin.yml | 2 +- .../com/fastasyncworldedit/core/configuration/Settings.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-bukkit/src/main/resources/plugin.yml b/worldedit-bukkit/src/main/resources/plugin.yml index b4f845265..cd12b1008 100644 --- a/worldedit-bukkit/src/main/resources/plugin.yml +++ b/worldedit-bukkit/src/main/resources/plugin.yml @@ -21,7 +21,7 @@ permissions: default: op children: fawe.bypass.regions: true - fawe.limit.*: true + fawe.limit.unlimited: true fawe.tips: default: op fawe.admin: diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index 672dcebe8..099386f00 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -102,7 +102,7 @@ public class Settings extends Config { public FaweLimit getLimit(Actor actor) { FaweLimit limit; - if (actor.hasPermission("fawe.bypass") || actor.hasPermission("fawe.limit.unlimited")) { + if (actor.hasPermission("fawe.limit.unlimited")) { return FaweLimit.MAX.copy(); } limit = new FaweLimit(); From 605743321f018738f00059bf14a76ab7e6a8993e Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Fri, 8 Dec 2023 07:30:08 +0100 Subject: [PATCH 086/466] Add support for 1.20.3 and 1.20.4 (#2512) * 1.20.3 * 1.20.3 ItemTypes * 1.20.3 * 1.20.3 * 1.20.4 * Fixup refractions * Move adapters to _4 --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- build.gradle.kts | 4 +- settings.gradle.kts | 2 +- .../adapter/ext/fawe/PaperweightAdapter.java | 2 +- .../adapters/adapter-1_20_4/build.gradle.kts | 17 + .../ext.fawe/v1_20_R3/PaperweightAdapter.java | 1019 ++++++ .../v1_20_R3/PaperweightDataConverters.java | 2801 +++++++++++++++++ .../v1_20_R3/PaperweightFakePlayer.java | 98 + .../PaperweightWorldNativeAccess.java | 181 ++ .../v1_20_R3/PaperweightBlockMaterial.java | 185 ++ .../fawe/v1_20_R3/PaperweightFaweAdapter.java | 617 ++++ .../PaperweightFaweWorldNativeAccess.java | 286 ++ .../fawe/v1_20_R3/PaperweightGetBlocks.java | 1181 +++++++ .../v1_20_R3/PaperweightGetBlocks_Copy.java | 254 ++ .../v1_20_R3/PaperweightMapChunkUtil.java | 34 + .../v1_20_R3/PaperweightPlatformAdapter.java | 719 +++++ .../v1_20_R3/PaperweightPostProcessor.java | 175 + .../PaperweightStarlightRelighter.java | 76 + .../PaperweightStarlightRelighterFactory.java | 25 + .../nbt/PaperweightLazyCompoundTag.java | 161 + .../fawe/v1_20_R3/regen/PaperweightRegen.java | 590 ++++ worldedit-bukkit/build.gradle.kts | 2 +- .../extent/reorder/MultiStageReorder.java | 5 + .../function/generator/FloraGenerator.java | 8 +- .../world/block/BlockCategories.java | 2 + .../worldedit/world/block/BlockTypes.java | 114 +- .../worldedit/world/entity/EntityTypes.java | 4 + .../sk89q/worldedit/world/item/ItemTypes.java | 118 +- 28 files changed, 8673 insertions(+), 9 deletions(-) create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightDataConverters.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightFakePlayer.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightWorldNativeAccess.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweWorldNativeAccess.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightMapChunkUtil.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPostProcessor.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighterFactory.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/nbt/PaperweightLazyCompoundTag.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/regen/PaperweightRegen.java diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 560478e0e..b687075ad 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -27,7 +27,7 @@ body: description: Which server version version you using? If your server version is not listed, it is not supported. Update to a supported version first. multiple: false options: - - '1.20.2' + - '1.20.4' - '1.20' - '1.19.4' - '1.18.2' diff --git a/build.gradle.kts b/build.gradle.kts index 02df265c0..390870651 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -83,7 +83,7 @@ allprojects { } applyCommonConfiguration() -val supportedVersions = listOf("1.17.1", "1.18.2", "1.19.4", "1.20", "1.20.2") +val supportedVersions = listOf("1.17.1", "1.18.2", "1.19.4", "1.20", "1.20.4") tasks { supportedVersions.forEach { @@ -97,7 +97,7 @@ tasks { } } runServer { - minecraftVersion("1.20.2") + minecraftVersion("1.20.4") pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile } .toTypedArray()) diff --git a/settings.gradle.kts b/settings.gradle.kts index d8b8012cf..6f9b3e8e0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,7 +2,7 @@ rootProject.name = "FastAsyncWorldEdit" include("worldedit-libs") -listOf("1_17_1", "1_18_2", "1_19_4", "1_20", "1_20_2").forEach { +listOf("1_17_1", "1_18_2", "1_19_4", "1_20", "1_20_2", "1_20_4").forEach { include("worldedit-bukkit:adapters:adapter-$it") } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java index 52974fb02..7d1fcc84e 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java @@ -198,7 +198,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter().paperDevBundle("1.20.3-R0.1-20231207.043048-3") + compileOnly(libs.paperlib) +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java new file mode 100644 index 000000000..2dc7d4b2b --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java @@ -0,0 +1,1019 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Sets; +import com.google.common.util.concurrent.Futures; +import com.mojang.datafixers.util.Either; +import com.mojang.serialization.Lifecycle; +import com.sk89q.jnbt.NBTConstants; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extension.platform.Watchdog; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +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.util.SideEffect; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.util.io.file.SafeFiles; +import com.sk89q.worldedit.util.nbt.BinaryTag; +import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; +import com.sk89q.worldedit.util.nbt.ByteBinaryTag; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; +import com.sk89q.worldedit.util.nbt.EndBinaryTag; +import com.sk89q.worldedit.util.nbt.FloatBinaryTag; +import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; +import com.sk89q.worldedit.util.nbt.IntBinaryTag; +import com.sk89q.worldedit.util.nbt.ListBinaryTag; +import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; +import com.sk89q.worldedit.util.nbt.LongBinaryTag; +import com.sk89q.worldedit.util.nbt.ShortBinaryTag; +import com.sk89q.worldedit.util.nbt.StringBinaryTag; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.RegenOptions; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.item.ItemType; +import net.minecraft.Util; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.util.StringRepresentable; +import net.minecraft.util.thread.BlockableEventLoop; +import net.minecraft.world.Clearable; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelSettings; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.StructureBlockEntity; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.WorldOptions; +import net.minecraft.world.level.storage.LevelStorageSource; +import net.minecraft.world.level.storage.PrimaryLevelData; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World.Environment; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_20_R3.CraftServer; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; +import org.bukkit.generator.ChunkGenerator; +import org.spigotmc.SpigotConfig; +import org.spigotmc.WatchdogThread; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.OptionalInt; +import java.util.OptionalLong; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +public final class PaperweightAdapter implements BukkitImplAdapter { + + private final Logger logger = Logger.getLogger(getClass().getCanonicalName()); + + private final Field serverWorldsField; + private final Method getChunkFutureMethod; + private final Field chunkProviderExecutorField; + private final Watchdog watchdog; + + // ------------------------------------------------------------------------ + // Code that may break between versions of Minecraft + // ------------------------------------------------------------------------ + + public PaperweightAdapter() throws NoSuchFieldException, NoSuchMethodException { + // A simple test + CraftServer.class.cast(Bukkit.getServer()); + + int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); + if (dataVersion != 3698) { + throw new UnsupportedClassVersionError("Not 1.20.4"); + } + + serverWorldsField = CraftServer.class.getDeclaredField("worlds"); + serverWorldsField.setAccessible(true); + + getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod( + Refraction.pickName("getChunkFutureMainThread", "c"), + int.class, int.class, ChunkStatus.class, boolean.class + ); + getChunkFutureMethod.setAccessible(true); + + chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField( + Refraction.pickName("mainThreadProcessor", "g") + ); + chunkProviderExecutorField.setAccessible(true); + + new PaperweightDataConverters(CraftMagicNumbers.INSTANCE.getDataVersion(), this).buildUnoptimized(); + + Watchdog watchdog; + try { + Class.forName("org.spigotmc.WatchdogThread"); + watchdog = new SpigotWatchdog(); + } catch (ClassNotFoundException | NoSuchFieldException e) { + try { + watchdog = new MojangWatchdog(((CraftServer) Bukkit.getServer()).getServer()); + } catch (NoSuchFieldException ex) { + watchdog = null; + } + } + this.watchdog = watchdog; + + try { + Class.forName("org.spigotmc.SpigotConfig"); + SpigotConfig.config.set("world-settings.faweregentempworld.verbose", false); + } catch (ClassNotFoundException ignored) { + } + } + + @Override + public DataFixer getDataFixer() { + return PaperweightDataConverters.INSTANCE; + } + + /** + * Read the given NBT data into the given tile entity. + * + * @param tileEntity the tile entity + * @param tag the tag + */ + static void readTagIntoTileEntity(net.minecraft.nbt.CompoundTag tag, BlockEntity tileEntity) { + tileEntity.load(tag); + tileEntity.setChanged(); + } + + /** + * Get the ID string of the given entity. + * + * @param entity the entity + * @return the entity ID + */ + private static String getEntityId(Entity entity) { + return EntityType.getKey(entity.getType()).toString(); + } + + /** + * Create an entity using the given entity ID. + * + * @param id the entity ID + * @param world the world + * @return an entity or null + */ + @Nullable + private static Entity createEntityFromId(String id, net.minecraft.world.level.Level world) { + return EntityType.byString(id).map(t -> t.create(world)).orElse(null); + } + + /** + * Write the given NBT data into the given entity. + * + * @param entity the entity + * @param tag the tag + */ + private static void readTagIntoEntity(net.minecraft.nbt.CompoundTag tag, Entity entity) { + entity.load(tag); + } + + /** + * Write the entity's NBT data to the given tag. + * + * @param entity the entity + * @param tag the tag + */ + private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag tag) { + entity.save(tag); + } + + private static Block getBlockFromType(BlockType blockType) { + + return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK).get(ResourceLocation.tryParse(blockType.getId())); + } + + private static Item getItemFromType(ItemType itemType) { + return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(itemType.getId())); + } + + @Override + public OptionalInt getInternalBlockStateId(BlockData data) { + net.minecraft.world.level.block.state.BlockState state = ((CraftBlockData) data).getState(); + int combinedId = Block.getId(state); + return combinedId == 0 && state.getBlock() != Blocks.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); + } + + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + Block mcBlock = getBlockFromType(state.getBlockType()); + net.minecraft.world.level.block.state.BlockState newState = mcBlock.defaultBlockState(); + Map, Object> states = state.getStates(); + newState = applyProperties(mcBlock.getStateDefinition(), newState, states); + final int combinedId = Block.getId(newState); + return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); + } + + @Override + public BlockState getBlock(Location location) { + checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); + int internalId = Block.getId(blockData); + BlockState state = BlockStateIdAccess.getBlockStateById(internalId); + if (state == null) { + org.bukkit.block.Block bukkitBlock = location.getBlock(); + state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } + + return state; + } + + @Override + public BaseBlock getFullBlock(Location location) { + BlockState state = getBlock(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + + // Read the NBT data + BlockEntity te = chunk.getBlockEntity(blockPos); + if (te != null) { + net.minecraft.nbt.CompoundTag tag = te.saveWithId(); + return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); + } + + return state.toBaseBlock(); + } + + private static final HashMap> biomeTypeToNMSCache = new HashMap<>(); + private static final HashMap, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); + + @Override + public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle())); + } + + private static net.minecraft.core.Direction adapt(Direction face) { + switch (face) { + case NORTH: + return net.minecraft.core.Direction.NORTH; + case SOUTH: + return net.minecraft.core.Direction.SOUTH; + case WEST: + return net.minecraft.core.Direction.WEST; + case EAST: + return net.minecraft.core.Direction.EAST; + case DOWN: + return net.minecraft.core.Direction.DOWN; + case UP: + default: + return net.minecraft.core.Direction.UP; + } + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private net.minecraft.world.level.block.state.BlockState applyProperties( + StateDefinition stateContainer, + net.minecraft.world.level.block.state.BlockState newState, + Map, Object> states + ) { + for (Map.Entry, Object> state : states.entrySet()) { + net.minecraft.world.level.block.state.properties.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.world.level.block.state.properties.EnumProperty) { + String enumName = (String) value; + value = ((net.minecraft.world.level.block.state.properties.EnumProperty) property) + .getValue(enumName).orElseThrow(() -> + new IllegalStateException( + "Enum property " + property.getName() + " does not contain " + enumName + ) + ); + } + + newState = newState.setValue( + (net.minecraft.world.level.block.state.properties.Property) property, + (Comparable) value + ); + } + return newState; + } + + @Override + public BaseEntity getEntity(org.bukkit.entity.Entity entity) { + checkNotNull(entity); + + CraftEntity craftEntity = ((CraftEntity) entity); + Entity mcEntity = craftEntity.getHandle(); + + // Do not allow creating of passenger entity snapshots, passengers are included in the vehicle entity + if (mcEntity.isPassenger()) { + return null; + } + + String id = getEntityId(mcEntity); + + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + readEntityIntoTag(mcEntity, tag); + return new BaseEntity( + com.sk89q.worldedit.world.entity.EntityTypes.get(id), + LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag)) + ); + } + + @Nullable + @Override + public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state) { + checkNotNull(location); + checkNotNull(state); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + ServerLevel worldServer = craftWorld.getHandle(); + + Entity createdEntity = createEntityFromId(state.getType().getId(), craftWorld.getHandle()); + + if (createdEntity != null) { + CompoundBinaryTag nativeTag = state.getNbt(); + if (nativeTag != null) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(nativeTag); + for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + readTagIntoEntity(tag, createdEntity); + } + + createdEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + + worldServer.addFreshEntity(createdEntity, SpawnReason.CUSTOM); + return createdEntity.getBukkitEntity(); + } else { + return null; + } + } + + // This removes all unwanted tags from the main entity and all its passengers + private void removeUnwantedEntityTagsRecursively(net.minecraft.nbt.CompoundTag tag) { + for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + + // Adapted from net.minecraft.world.entity.EntityType#loadEntityRecursive + if (tag.contains("Passengers", NBTConstants.TYPE_LIST)) { + net.minecraft.nbt.ListTag nbttaglist = tag.getList("Passengers", NBTConstants.TYPE_COMPOUND); + + for (int i = 0; i < nbttaglist.size(); ++i) { + removeUnwantedEntityTagsRecursively(nbttaglist.getCompound(i)); + } + } + } + + @Override + public Component getRichBlockName(BlockType blockType) { + return TranslatableComponent.of(getBlockFromType(blockType).getDescriptionId()); + } + + @Override + public Component getRichItemName(ItemType itemType) { + return TranslatableComponent.of(getItemFromType(itemType).getDescriptionId()); + } + + @Override + public Component getRichItemName(BaseItemStack itemStack) { + return TranslatableComponent.of(CraftItemStack.asNMSCopy(BukkitAdapter.adapt(itemStack)).getDescriptionId()); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static final LoadingCache> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { + @Override + public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { + if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else if (state instanceof DirectionProperty) { + return new DirectionalProperty(state.getName(), + (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); + } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + return new EnumProperty(state.getName(), + (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); + } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else { + throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); + } + } + }); + + @SuppressWarnings({ "rawtypes" }) + @Override + public Map> getProperties(BlockType blockType) { + Map> properties = new TreeMap<>(); + Block block = getBlockFromType(blockType); + StateDefinition blockStateList = + block.getStateDefinition(); + for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { + Property property = PROPERTY_CACHE.getUnchecked(state); + properties.put(property.getName(), property); + } + return properties; + } + + @Override + public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { + ((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create( + new StructureBlockEntity( + new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()), + Blocks.STRUCTURE_BLOCK.defaultBlockState() + ), + __ -> (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) + )); + } + + @Override + public void sendFakeOP(Player player) { + ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( + ((CraftPlayer) player).getHandle(), (byte) 28 + )); + } + + @Override + public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { + ItemStack stack = new ItemStack( + DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().getId())), + item.getAmount() + ); + stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData()))); + return CraftItemStack.asCraftMirror(stack); + } + + @Override + public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { + final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); + final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); + weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); + return weStack; + } + + private final LoadingCache fakePlayers + = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); + + @Override + public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) { + CraftWorld craftWorld = (CraftWorld) world; + ServerLevel worldServer = craftWorld.getHandle(); + ItemStack stack = CraftItemStack.asNMSCopy(BukkitAdapter.adapt(item instanceof BaseItemStack + ? ((BaseItemStack) item) : new BaseItemStack(item.getType(), item.getNbtData(), 1))); + stack.setTag((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData())); + + PaperweightFakePlayer fakePlayer; + try { + fakePlayer = fakePlayers.get(worldServer); + } catch (ExecutionException ignored) { + return false; + } + fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); + fakePlayer.absMoveTo(position.getBlockX(), position.getBlockY(), position.getBlockZ(), + (float) face.toVector().toYaw(), (float) face.toVector().toPitch()); + + final BlockPos blockPos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos); + final net.minecraft.core.Direction enumFacing = adapt(face); + BlockHitResult rayTrace = new BlockHitResult(blockVec, enumFacing, blockPos, false); + UseOnContext context = new UseOnContext(fakePlayer, InteractionHand.MAIN_HAND, rayTrace); + InteractionResult result = stack.useOn(context); + if (result != InteractionResult.SUCCESS) { + if (worldServer.getBlockState(blockPos).use(worldServer, fakePlayer, InteractionHand.MAIN_HAND, rayTrace).consumesAction()) { + result = InteractionResult.SUCCESS; + } else { + result = stack.getItem().use(worldServer, fakePlayer, InteractionHand.MAIN_HAND).getResult(); + } + } + + return result == InteractionResult.SUCCESS; + } + + @Override + public boolean canPlaceAt(org.bukkit.World world, BlockVector3 position, BlockState blockState) { + int internalId = BlockStateIdAccess.getBlockStateId(blockState); + net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId); + return blockData.canSurvive(((CraftWorld) world).getHandle(), new BlockPos(position.getX(), position.getY(), position.getZ())); + } + + @Override + public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) { + try { + doRegen(bukkitWorld, region, extent, options); + } catch (Exception e) { + throw new IllegalStateException("Regen failed.", e); + } + + return true; + } + + private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { + Environment env = bukkitWorld.getEnvironment(); + ChunkGenerator gen = bukkitWorld.getGenerator(); + + Path tempDir = Files.createTempDirectory("WorldEditWorldGen"); + LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir); + ResourceKey worldDimKey = getWorldDimKey(env); + try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { + ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); + PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() + .getWorldData().overworldData(); + WorldOptions originalOpts = levelProperties.worldGenOptions(); + + long seed = options.getSeed().orElse(originalWorld.getSeed()); + WorldOptions newOpts = options.getSeed().isPresent() + ? originalOpts.withSeed(OptionalLong.of(seed)) + : originalOpts; + + LevelSettings newWorldSettings = new LevelSettings( + "faweregentempworld", + levelProperties.settings.gameType(), + levelProperties.settings.hardcore(), + levelProperties.settings.difficulty(), + levelProperties.settings.allowCommands(), + levelProperties.settings.gameRules(), + levelProperties.settings.getDataConfiguration() + ); + + PrimaryLevelData.SpecialWorldProperty specialWorldProperty = + levelProperties.isFlatWorld() + ? PrimaryLevelData.SpecialWorldProperty.FLAT + : levelProperties.isDebugWorld() + ? PrimaryLevelData.SpecialWorldProperty.DEBUG + : PrimaryLevelData.SpecialWorldProperty.NONE; + + PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable()); + + ServerLevel freshWorld = new ServerLevel( + originalWorld.getServer(), + originalWorld.getServer().executor, + session, newWorldData, + originalWorld.dimension(), + new LevelStem( + originalWorld.dimensionTypeRegistration(), + originalWorld.getChunkSource().getGenerator() + ), + new NoOpWorldLoadListener(), + originalWorld.isDebug(), + seed, + ImmutableList.of(), + false, + originalWorld.getRandomSequences(), + env, + gen, + bukkitWorld.getBiomeProvider() + ); + try { + regenForWorld(region, extent, freshWorld, options); + } finally { + freshWorld.getChunkSource().close(false); + } + } finally { + try { + @SuppressWarnings("unchecked") + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); + map.remove("faweregentempworld"); + } catch (IllegalAccessException ignored) { + } + SafeFiles.tryHardToDeleteDir(tempDir); + } + } + + private BiomeType adapt(ServerLevel serverWorld, Biome origBiome) { + ResourceLocation key = serverWorld.registryAccess().registryOrThrow(Registries.BIOME).getKey(origBiome); + if (key == null) { + return null; + } + return BiomeTypes.get(key.toString()); + } + + @SuppressWarnings("unchecked") + private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld, RegenOptions options) throws WorldEditException { + List> chunkLoadings = submitChunkLoadTasks(region, serverWorld); + BlockableEventLoop executor; + try { + executor = (BlockableEventLoop) chunkProviderExecutorField.get(serverWorld.getChunkSource()); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Couldn't get executor for chunk loading.", e); + } + executor.managedBlock(() -> { + // bail out early if a future fails + if (chunkLoadings.stream().anyMatch(ftr -> + ftr.isDone() && Futures.getUnchecked(ftr) == null + )) { + return false; + } + return chunkLoadings.stream().allMatch(CompletableFuture::isDone); + }); + Map chunks = new HashMap<>(); + for (CompletableFuture future : chunkLoadings) { + @Nullable + ChunkAccess chunk = future.getNow(null); + checkState(chunk != null, "Failed to generate a chunk, regen failed."); + chunks.put(chunk.getPos(), chunk); + } + + for (BlockVector3 vec : region) { + BlockPos pos = new BlockPos(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()); + ChunkAccess chunk = chunks.get(new ChunkPos(pos)); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(pos); + int internalId = Block.getId(blockData); + BlockStateHolder state = BlockStateIdAccess.getBlockStateById(internalId); + Objects.requireNonNull(state); + BlockEntity blockEntity = chunk.getBlockEntity(pos); + if (blockEntity != null) { + net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); + state = state.toBaseBlock(((CompoundBinaryTag) toNativeBinary(tag))); + } + extent.setBlock(vec, state.toBaseBlock()); + if (options.shouldRegenBiomes()) { + Biome origBiome = chunk.getNoiseBiome(vec.getX(), vec.getY(), vec.getZ()).value(); + BiomeType adaptedBiome = adapt(serverWorld, origBiome); + if (adaptedBiome != null) { + extent.setBiome(vec, adaptedBiome); + } + } + } + } + + @SuppressWarnings("unchecked") + private List> submitChunkLoadTasks(Region region, ServerLevel serverWorld) { + ServerChunkCache chunkManager = serverWorld.getChunkSource(); + List> chunkLoadings = new ArrayList<>(); + // Pre-gen all the chunks + for (BlockVector2 chunk : region.getChunks()) { + try { + //noinspection unchecked + chunkLoadings.add( + ((CompletableFuture>) + getChunkFutureMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) + .thenApply(either -> either.left().orElse(null)) + ); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException("Couldn't load chunk for regen.", e); + } + } + return chunkLoadings; + } + + private ResourceKey getWorldDimKey(Environment env) { + switch (env) { + case NETHER: + return LevelStem.NETHER; + case THE_END: + return LevelStem.END; + case NORMAL: + default: + return LevelStem.OVERWORLD; + } + } + + private static final Set SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( + SideEffect.NEIGHBORS, + SideEffect.LIGHTING, + SideEffect.VALIDATION, + SideEffect.ENTITY_AI, + SideEffect.EVENTS, + SideEffect.UPDATE + ); + + @Override + public Set getSupportedSideEffects() { + return SUPPORTED_SIDE_EFFECTS; + } + + @Override + public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + + BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + if (entity instanceof Clearable) { + ((Clearable) entity).clearContent(); + return true; + } + return false; + } + + // ------------------------------------------------------------------------ + // Code that is less likely to break + // ------------------------------------------------------------------------ + + /** + * Converts from a non-native NMS NBT structure to a native WorldEdit NBT + * structure. + * + * @param foreign non-native NMS NBT structure + * @return native WorldEdit NBT structure + */ + @Override + public BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { + if (foreign == null) { + return null; + } + if (foreign instanceof net.minecraft.nbt.CompoundTag) { + Map values = new HashMap<>(); + Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); + + for (String str : foreignKeys) { + net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); + values.put(str, toNativeBinary(base)); + } + return CompoundBinaryTag.from(values); + } else if (foreign instanceof net.minecraft.nbt.ByteTag) { + return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); + } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { + return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); + } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { + return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); + } else if (foreign instanceof net.minecraft.nbt.FloatTag) { + return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); + } else if (foreign instanceof net.minecraft.nbt.IntTag) { + return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); + } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { + return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); + } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { + return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); + } else if (foreign instanceof net.minecraft.nbt.ListTag) { + try { + return toNativeList((net.minecraft.nbt.ListTag) foreign); + } catch (Throwable e) { + logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); + return ListBinaryTag.empty(); + } + } else if (foreign instanceof net.minecraft.nbt.LongTag) { + return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); + } else if (foreign instanceof net.minecraft.nbt.ShortTag) { + return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); + } else if (foreign instanceof net.minecraft.nbt.StringTag) { + return StringBinaryTag.of(foreign.getAsString()); + } else if (foreign instanceof net.minecraft.nbt.EndTag) { + return EndBinaryTag.get(); + } else { + throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); + } + } + + /** + * Convert a foreign NBT list tag into a native WorldEdit one. + * + * @param foreign the foreign tag + * @return the converted tag + * @throws SecurityException on error + * @throws IllegalArgumentException on error + */ + private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { + ListBinaryTag.Builder values = ListBinaryTag.builder(); + + for (net.minecraft.nbt.Tag tag : foreign) { + values.add(toNativeBinary(tag)); + } + + return values.build(); + } + + /** + * Converts a WorldEdit-native NBT structure to a NMS structure. + * + * @param foreign structure to convert + * @return non-native structure + */ + @Override + public net.minecraft.nbt.Tag fromNativeBinary(BinaryTag foreign) { + if (foreign == null) { + return null; + } + if (foreign instanceof CompoundBinaryTag) { + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + for (String key : ((CompoundBinaryTag) foreign).keySet()) { + tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); + } + return tag; + } else if (foreign instanceof ByteBinaryTag) { + return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); + } else if (foreign instanceof ByteArrayBinaryTag) { + return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); + } else if (foreign instanceof DoubleBinaryTag) { + return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); + } else if (foreign instanceof FloatBinaryTag) { + return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); + } else if (foreign instanceof IntBinaryTag) { + return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); + } else if (foreign instanceof IntArrayBinaryTag) { + return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); + } else if (foreign instanceof LongArrayBinaryTag) { + return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); + } else if (foreign instanceof ListBinaryTag) { + net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); + ListBinaryTag foreignList = (ListBinaryTag) foreign; + for (BinaryTag t : foreignList) { + tag.add(fromNativeBinary(t)); + } + return tag; + } else if (foreign instanceof LongBinaryTag) { + return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); + } else if (foreign instanceof ShortBinaryTag) { + return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); + } else if (foreign instanceof StringBinaryTag) { + return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); + } else if (foreign instanceof EndBinaryTag) { + return net.minecraft.nbt.EndTag.INSTANCE; + } else { + throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); + } + } + + @Override + public boolean supportsWatchdog() { + return watchdog != null; + } + + @Override + public void tickWatchdog() { + watchdog.tick(); + } + + private class SpigotWatchdog implements Watchdog { + private final Field instanceField; + private final Field lastTickField; + + SpigotWatchdog() throws NoSuchFieldException { + Field instanceField = WatchdogThread.class.getDeclaredField("instance"); + instanceField.setAccessible(true); + this.instanceField = instanceField; + + Field lastTickField = WatchdogThread.class.getDeclaredField("lastTick"); + lastTickField.setAccessible(true); + this.lastTickField = lastTickField; + } + + @Override + public void tick() { + try { + WatchdogThread instance = (WatchdogThread) this.instanceField.get(null); + if ((long) lastTickField.get(instance) != 0) { + WatchdogThread.tick(); + } + } catch (IllegalAccessException e) { + logger.log(Level.WARNING, "Failed to tick watchdog", e); + } + } + } + + private static class MojangWatchdog implements Watchdog { + private final DedicatedServer server; + private final Field tickField; + + MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { + this.server = server; + Field tickField = MinecraftServer.class.getDeclaredField( + Refraction.pickName("nextTickTime", "ah") + ); + if (tickField.getType() != long.class) { + throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); + } + tickField.setAccessible(true); + this.tickField = tickField; + } + + @Override + public void tick() { + try { + tickField.set(server, Util.getMillis()); + } catch (IllegalAccessException ignored) { + } + } + } + + private static class NoOpWorldLoadListener implements ChunkProgressListener { + @Override + public void updateSpawnPos(ChunkPos spawnPos) { + } + + @Override + public void onStatusChange(ChunkPos pos, @org.jetbrains.annotations.Nullable ChunkStatus status) { + } + + @Override + public void start() { + } + + @Override + public void stop() { + } + + @Override + public void setChunkRadius(int radius) { + } + } +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightDataConverters.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightDataConverters.java new file mode 100644 index 000000000..175174b75 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightDataConverters.java @@ -0,0 +1,2801 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3; + +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; +import com.mojang.datafixers.DSL.TypeReference; +import com.mojang.datafixers.DataFixer; +import com.mojang.datafixers.DataFixerBuilder; +import com.mojang.datafixers.schemas.Schema; +import com.mojang.serialization.Dynamic; +import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3.PaperweightAdapter; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import net.minecraft.core.Direction; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import net.minecraft.util.StringUtil; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.world.item.DyeColor; +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({ "rawtypes", "unchecked" }) +public class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { + + //FAWE start - BinaryTag + @SuppressWarnings("unchecked") + @Override + public T fixUp(FixType type, T original, int srcVer) { + if (type == FixTypes.CHUNK) { + return (T) fixChunk((CompoundBinaryTag) original, srcVer); + } else if (type == FixTypes.BLOCK_ENTITY) { + return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); + } else if (type == FixTypes.ENTITY) { + return (T) fixEntity((CompoundBinaryTag) 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 CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); + net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); + return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + } + + private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); + net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); + return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + } + + private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); + net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); + return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + } + //FAWE end + + 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(References.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.contains("Properties", 10)) { + sb.append('['); + net.minecraft.nbt.CompoundTag props = tagCompound.getCompound("Properties"); + sb.append(props.getAllKeys().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, References.BIOME); + } + + private String fixItemType(String key, int srcVer) { + return fixName(key, srcVer, References.ITEM_NAME); + } + + private static String fixName(String key, int srcVer, TypeReference type) { + return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, net.minecraft.nbt.StringTag.valueOf(key)), srcVer, DATA_VERSION) + .getValue().getAsString(); + } + + private final PaperweightAdapter adapter; + + private static final NbtOps OPS_NBT = NbtOps.INSTANCE; + private static final int LEGACY_VERSION = 1343; + private static int DATA_VERSION; + public static PaperweightDataConverters 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(References.LEVEL), + PLAYER(References.PLAYER), + CHUNK(References.CHUNK), + BLOCK_ENTITY(References.BLOCK_ENTITY), + ENTITY(References.ENTITY), + ITEM_INSTANCE(References.ITEM_STACK), + OPTIONS(References.OPTIONS), + STRUCTURE(References.STRUCTURE); + + private final TypeReference type; + + LegacyType(TypeReference type) { + this.type = type; + DFU_TO_LEGACY.put(type.typeName(), this); + } + + public TypeReference getDFUType() { + return type; + } + } + + public PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { + super(dataVersion); + DATA_VERSION = dataVersion; + INSTANCE = this; + this.adapter = adapter; + registerConverters(); + registerInspectors(); + } + + + // Called after fixers are built and ready for FIXING + @Override + public DataFixer buildUnoptimized() { + return this.fixer = new WrappedDataFixer(DataFixers.getDataFixer()); + } + + @Override + public DataFixer buildOptimized(final Set requiredTypes, Executor executor) { + return buildUnoptimized(); + } + + @SuppressWarnings("unchecked") + 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 = PaperweightDataConverters.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 = PaperweightDataConverters.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.contains("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 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, 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.contains(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.contains(key, 9)) { + net.minecraft.nbt.ListTag nbttaglist = nbttagcompound.getList(key, 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set(j, convert(LegacyType.ITEM_INSTANCE, nbttaglist.getCompound(j), sourceVer, targetVer)); + } + } + + } + + private static class DataConverterEquipment implements DataConverter { + + DataConverterEquipment() { + } + + public int getDataVersion() { + return 100; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + net.minecraft.nbt.ListTag nbttaglist = cmp.getList("Equipment", 10); + net.minecraft.nbt.ListTag nbttaglist1; + + if (!nbttaglist.isEmpty() && !cmp.contains("HandItems", 10)) { + nbttaglist1 = new net.minecraft.nbt.ListTag(); + nbttaglist1.add(nbttaglist.get(0)); + nbttaglist1.add(new net.minecraft.nbt.CompoundTag()); + cmp.put("HandItems", nbttaglist1); + } + + if (nbttaglist.size() > 1 && !cmp.contains("ArmorItem", 10)) { + nbttaglist1 = new net.minecraft.nbt.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.contains("DropChances", 9)) { + nbttaglist1 = cmp.getList("DropChances", 5); + net.minecraft.nbt.ListTag nbttaglist2; + + if (!cmp.contains("HandDropChances", 10)) { + nbttaglist2 = new net.minecraft.nbt.ListTag(); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(0))); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(0.0F)); + cmp.put("HandDropChances", nbttaglist2); + } + + if (!cmp.contains("ArmorDropChances", 10)) { + nbttaglist2 = new net.minecraft.nbt.ListTag(); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(1))); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(2))); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(3))); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(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); + } + } + + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (!cmp.contains("tag", 10)) { + return cmp; + } else { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("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.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 { + + DataInspectorEntity() { + } + + 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.contains("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; + + 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (this.key.equals(new ResourceLocation(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) { + PaperweightDataConverters.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) { + PaperweightDataConverters.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.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"; + // Paper start + materials[409] = "minecraft:prismarine_shard"; + materials[410] = "minecraft:prismarine_crystals"; + materials[411] = "minecraft:rabbit"; + materials[412] = "minecraft:cooked_rabbit"; + materials[413] = "minecraft:rabbit_stew"; + materials[414] = "minecraft:rabbit_foot"; + materials[415] = "minecraft:rabbit_hide"; + materials[416] = "minecraft:armor_stand"; + materials[423] = "minecraft:mutton"; + materials[424] = "minecraft:cooked_mutton"; + materials[425] = "minecraft:banner"; + materials[426] = "minecraft:end_crystal"; + materials[427] = "minecraft:spruce_door"; + materials[428] = "minecraft:birch_door"; + materials[429] = "minecraft:jungle_door"; + materials[430] = "minecraft:acacia_door"; + materials[431] = "minecraft:dark_oak_door"; + materials[432] = "minecraft:chorus_fruit"; + materials[433] = "minecraft:chorus_fruit_popped"; + materials[434] = "minecraft:beetroot"; + materials[435] = "minecraft:beetroot_seeds"; + materials[436] = "minecraft:beetroot_soup"; + materials[437] = "minecraft:dragon_breath"; + materials[438] = "minecraft:splash_potion"; + materials[439] = "minecraft:spectral_arrow"; + materials[440] = "minecraft:tipped_arrow"; + materials[441] = "minecraft:lingering_potion"; + materials[442] = "minecraft:shield"; + materials[443] = "minecraft:elytra"; + materials[444] = "minecraft:spruce_boat"; + materials[445] = "minecraft:birch_boat"; + materials[446] = "minecraft:jungle_boat"; + materials[447] = "minecraft:acacia_boat"; + materials[448] = "minecraft:dark_oak_boat"; + materials[449] = "minecraft:totem_of_undying"; + materials[450] = "minecraft:shulker_shell"; + materials[452] = "minecraft:iron_nugget"; + materials[453] = "minecraft:knowledge_book"; + // Paper end + } + } + + 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.contains("tag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + + if (nbttagcompound2.contains("Base", 99)) { + cmp.putShort("Damage", (short) (nbttagcompound2.getShort("Base") & 15)); + if (nbttagcompound1.contains("display", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound3 = nbttagcompound1.getCompound("display"); + + if (nbttagcompound3.contains("Lore", 9)) { + net.minecraft.nbt.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.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 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.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("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.contains("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.contains("SpawnPotentials", 9)) { + net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int i = 0; i < nbttaglist.size(); ++i) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist.getCompound(i); + + if (nbttagcompound2.contains("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.contains("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.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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("EntityHorse".equals(cmp.getString("id")) && !cmp.contains("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.contains("Facing", 99)) { + Direction enumdirection; + + if (cmp.contains("Direction", 99)) { + enumdirection = Direction.from2DDataValue(cmp.getByte("Direction")); + cmp.putInt("TileX", cmp.getInt("TileX") + enumdirection.getStepX()); + cmp.putInt("TileY", cmp.getInt("TileY") + enumdirection.getStepY()); + cmp.putInt("TileZ", cmp.getInt("TileZ") + enumdirection.getStepZ()); + cmp.remove("Direction"); + if (flag1 && cmp.contains("ItemRotation", 99)) { + cmp.putByte("ItemRotation", (byte) (cmp.getByte("ItemRotation") * 2)); + } + } else { + enumdirection = Direction.from2DDataValue(cmp.getByte("Dir")); + cmp.remove("Dir"); + } + + cmp.putByte("Facing", (byte) enumdirection.get2DDataValue()); + } + + 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) { + net.minecraft.nbt.ListTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + while (cmp.contains("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) { + net.minecraft.nbt.ListTag nbttaglist = new net.minecraft.nbt.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.contains("pages", 9)) { + net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("pages", 8); + + for (int i = 0; i < nbttaglist.size(); ++i) { + String s = nbttaglist.getString(i); + Component object = null; + + if (!"null".equals(s) && !StringUtil.isNullOrEmpty(s)) { + if ((s.charAt(0) != 34 || s.charAt(s.length() - 1) != 34) && (s.charAt(0) != 123 || s.charAt(s.length() - 1) != 125)) { + object = Component.literal(s); + } else { + try { + object = GsonHelper.fromJson(DataConverterSignText.a, s, Component.class, true); + if (object == null) { + object = Component.literal(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = Component.Serializer.fromJson(s); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = Component.Serializer.fromJsonLenient(s); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = Component.literal(s); + } + } + } else { + object = Component.literal(""); + } + + nbttaglist.set(i, net.minecraft.nbt.StringTag.valueOf(Component.Serializer.toJson(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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 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 0: + default: + break; + + 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"); + } + + 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 0: + default: + cmp.putString("id", "Horse"); + break; + + 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"); + } + + 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.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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:shulker_box".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("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.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 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(PaperweightDataConverters.class); + + DataConverterBedBlock() { + } + + public int getDataVersion() { + return 1125; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + try { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); + int i = nbttagcompound1.getInt("xPos"); + int j = nbttagcompound1.getInt("zPos"); + net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("TileEntities", 10); + net.minecraft.nbt.ListTag nbttaglist1 = nbttagcompound1.getList("Sections", 10); + + for (int k = 0; k < nbttaglist1.size(); ++k) { + net.minecraft.nbt.CompoundTag 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; + net.minecraft.nbt.CompoundTag nbttagcompound3 = new net.minecraft.nbt.CompoundTag(); + + nbttagcompound3.putString("id", "bed"); + nbttagcompound3.putInt("x", i1 + (i << 4)); + nbttagcompound3.putInt("y", j1 + (b0 << 4)); + nbttagcompound3.putInt("z", k1 + (j << 4)); + nbttaglist.add(nbttagcompound3); + } + } + } + } catch (Exception exception) { + DataConverterBedBlock.a.warn("Unable to datafix Bed blocks, level format may be missing tags."); + } + + return cmp; + } + } + + private static class DataConverterBedItem implements DataConverter { + + DataConverterBedItem() { + } + + public int getDataVersion() { + return 1125; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:bed".equals(cmp.getString("id")) && cmp.getShort("Damage") == 0) { + cmp.putShort("Damage", (short) DyeColor.RED.getId()); + } + + return cmp; + } + } + + private static class DataConverterSignText implements DataConverter { + + public static final Gson a = new GsonBuilder().registerTypeAdapter(Component.class, new JsonDeserializer() { + MutableComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { + if (jsonelement.isJsonPrimitive()) { + return Component.literal(jsonelement.getAsString()); + } else if (jsonelement.isJsonArray()) { + JsonArray jsonarray = jsonelement.getAsJsonArray(); + MutableComponent ichatbasecomponent = null; + Iterator iterator = jsonarray.iterator(); + + while (iterator.hasNext()) { + JsonElement jsonelement1 = (JsonElement) iterator.next(); + MutableComponent ichatbasecomponent1 = this.a(jsonelement1, jsonelement1.getClass(), jsondeserializationcontext); + + if (ichatbasecomponent == null) { + ichatbasecomponent = ichatbasecomponent1; + } else { + ichatbasecomponent.append(ichatbasecomponent1); + } + } + + return ichatbasecomponent; + } 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); + Component object = null; + + if (!"null".equals(s1) && !StringUtil.isNullOrEmpty(s1)) { + if ((s1.charAt(0) != 34 || s1.charAt(s1.length() - 1) != 34) && (s1.charAt(0) != 123 || s1.charAt(s1.length() - 1) != 125)) { + object = Component.literal(s1); + } else { + try { + object = GsonHelper.fromJson(DataConverterSignText.a, s1, Component.class, true); + if (object == null) { + object = Component.literal(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = Component.Serializer.fromJson(s1); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = Component.Serializer.fromJsonLenient(s1); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = Component.literal(s1); + } + } + } else { + object = Component.literal(""); + } + + nbttagcompound.putString(s, Component.Serializer.toJson(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.contains("RootVehicle", 10)) { + net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + net.minecraft.nbt.ListTag nbttaglist; + int j; + net.minecraft.nbt.CompoundTag nbttagcompound1; + + if (cmp.contains("entities", 9)) { + nbttaglist = cmp.getList("entities", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttagcompound1 = (net.minecraft.nbt.CompoundTag) 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 = (net.minecraft.nbt.CompoundTag) 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.contains("Level", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); + net.minecraft.nbt.ListTag 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, (net.minecraft.nbt.CompoundTag) 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, (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.contains("Passengers", 9)) { + net.minecraft.nbt.ListTag 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 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.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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (entityVillager.equals(new ResourceLocation(cmp.getString("id"))) && cmp.contains("Offers", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Offers"); + + if (nbttagcompound1.contains("Recipes", 9)) { + net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("Recipes", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (tileEntityMobSpawner.equals(new ResourceLocation(cmp.getString("id")))) { + if (cmp.contains("SpawnPotentials", 9)) { + net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightFakePlayer.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightFakePlayer.java new file mode 100644 index 000000000..c27f4a59a --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightFakePlayer.java @@ -0,0 +1,98 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3; + +import com.mojang.authlib.GameProfile; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.stats.Stat; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.player.ChatVisiblity; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.phys.Vec3; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + +import java.util.OptionalInt; +import java.util.UUID; + +class PaperweightFakePlayer extends ServerPlayer { + private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]"); + private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D); + private static final ClientInformation FAKE_CLIENT_INFO = new ClientInformation( + "en_US", 16, ChatVisiblity.FULL, true, 0, HumanoidArm.LEFT, false, false + ); + + PaperweightFakePlayer(ServerLevel world) { + super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE, FAKE_CLIENT_INFO); + } + + @Override + public Vec3 position() { + return ORIGIN; + } + + @Override + public void tick() { + } + + @Override + public void die(DamageSource damagesource) { + } + + @Override + public Entity changeDimension(ServerLevel worldserver, TeleportCause cause) { + return this; + } + + @Override + public OptionalInt openMenu(MenuProvider factory) { + return OptionalInt.empty(); + } + + @Override + public void updateOptions(ClientInformation clientOptions) { + } + + @Override + public void displayClientMessage(Component message, boolean actionBar) { + } + + @Override + public void awardStat(Stat stat, int amount) { + } + + @Override + public void awardStat(Stat stat) { + } + + @Override + public boolean isInvulnerableTo(DamageSource damageSource) { + return true; + } + + @Override + public void openTextEdit(SignBlockEntity sign, boolean front) { + } +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightWorldNativeAccess.java new file mode 100644 index 000000000..b50ead936 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightWorldNativeAccess.java @@ -0,0 +1,181 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3; + +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import com.sk89q.worldedit.world.block.BlockState; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.FullChunkStatus; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.chunk.LevelChunk; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; +import org.bukkit.event.block.BlockPhysicsEvent; + +import java.lang.ref.WeakReference; +import java.util.Objects; +import javax.annotation.Nullable; + +public class PaperweightWorldNativeAccess implements WorldNativeAccess { + private static final int UPDATE = 1; + private static final int NOTIFY = 2; + + private final PaperweightAdapter adapter; + private final WeakReference world; + private SideEffectSet sideEffectSet; + + public PaperweightWorldNativeAccess(PaperweightAdapter adapter, WeakReference world) { + this.adapter = adapter; + this.world = world; + } + + private ServerLevel getWorld() { + return Objects.requireNonNull(world.get(), "The reference to the world was lost"); + } + + @Override + public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + @Override + public LevelChunk getChunk(int x, int z) { + return getWorld().getChunk(x, z); + } + + @Override + public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) { + int stateId = BlockStateIdAccess.getBlockStateId(state); + return BlockStateIdAccess.isValidInternalId(stateId) + ? Block.stateById(stateId) + : ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); + } + + @Override + public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk chunk, BlockPos position) { + return chunk.getBlockState(position); + } + + @Nullable + @Override + public net.minecraft.world.level.block.state.BlockState setBlockState(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState state) { + return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE)); + } + + @Override + public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(net.minecraft.world.level.block.state.BlockState block, BlockPos position) { + return Block.updateFromNeighbourShapes(block, getWorld(), position); + } + + @Override + public BlockPos getPosition(int x, int y, int z) { + return new BlockPos(x, y, z); + } + + @Override + public void updateLightingForBlock(BlockPos position) { + getWorld().getChunkSource().getLightEngine().checkBlock(position); + } + + @Override + public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { + return false; + } + + @Override + public void notifyBlockUpdate(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { + if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { + getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY); + } + } + + @Override + public boolean isChunkTicking(LevelChunk chunk) { + return chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING); + } + + @Override + public void markBlockChanged(LevelChunk chunk, BlockPos position) { + if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { + getWorld().getChunkSource().blockChanged(position); + } + } + + @Override + public void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { + ServerLevel world = getWorld(); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + world.updateNeighborsAt(pos, oldState.getBlock()); + } else { + // When we don't want events, manually run the physics without them. + Block block = oldState.getBlock(); + fireNeighborChanged(pos, world, block, pos.west()); + fireNeighborChanged(pos, world, block, pos.east()); + fireNeighborChanged(pos, world, block, pos.below()); + fireNeighborChanged(pos, world, block, pos.above()); + fireNeighborChanged(pos, world, block, pos.north()); + fireNeighborChanged(pos, world, block, pos.south()); + } + if (newState.hasAnalogOutputSignal()) { + world.updateNeighbourForOutputSignal(pos, newState.getBlock()); + } + } + + // Not sure why neighborChanged is deprecated + @SuppressWarnings("deprecation") + private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { + world.getBlockState(neighborPos).neighborChanged(world, neighborPos, block, pos, false); + } + + @Override + public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) { + ServerLevel world = getWorld(); + // a == updateNeighbors + // b == updateDiagonalNeighbors + oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + CraftWorld craftWorld = world.getWorld(); + BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState)); + world.getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + } + newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit); + newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); + } + + @Override + public void onBlockStateChange(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { + getWorld().onBlockStateChange(pos, oldState, newState); + } + + @Override + public void flush() { + + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java new file mode 100644 index 000000000..edbe268fe --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java @@ -0,0 +1,185 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; + +import com.google.common.base.Suppliers; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.util.ReflectionUtil; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.EmptyBlockGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.LiquidBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.PushReaction; +import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; + +public class PaperweightBlockMaterial implements BlockMaterial { + + private final Block block; + private final BlockState blockState; + private final boolean isTranslucent; + private final CraftBlockData craftBlockData; + private final org.bukkit.Material craftMaterial; + private final int opacity; + private final CompoundTag tile; + + public PaperweightBlockMaterial(Block block) { + this(block, block.defaultBlockState()); + } + + public PaperweightBlockMaterial(Block block, BlockState blockState) { + this.block = block; + this.blockState = blockState; + this.craftBlockData = CraftBlockData.fromData(blockState); + this.craftMaterial = craftBlockData.getMaterial(); + BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, + Refraction.pickName("properties", "aP")); + this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo, + Refraction.pickName("canOcclude", "n") + ); + opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); + BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity( + BlockPos.ZERO, + blockState + ); + tile = tileEntity == null + ? null + : new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); + } + + public Block getBlock() { + return block; + } + + public BlockState getState() { + return blockState; + } + + public CraftBlockData getCraftBlockData() { + return craftBlockData; + } + + @Override + public boolean isAir() { + return blockState.isAir(); + } + + @Override + public boolean isFullCube() { + return craftMaterial.isOccluding(); + } + + @Override + public boolean isOpaque() { + return blockState.isOpaque(); + } + + @Override + public boolean isPowerSource() { + return blockState.isSignalSource(); + } + + @Override + public boolean isLiquid() { + // TODO: Better check ? + return block instanceof LiquidBlock; + } + + @Override + public boolean isSolid() { + // TODO: Replace + return blockState.isSolid(); + } + + @Override + public float getHardness() { + return craftBlockData.getState().destroySpeed; + } + + @Override + public float getResistance() { + return block.getExplosionResistance(); + } + + @Override + public float getSlipperiness() { + return block.getFriction(); + } + + @Override + public int getLightValue() { + return blockState.getLightEmission(); + } + + @Override + public int getLightOpacity() { + return opacity; + } + + @Override + public boolean isFragileWhenPushed() { + return blockState.getPistonPushReaction() == PushReaction.DESTROY; + } + + @Override + public boolean isUnpushable() { + return blockState.getPistonPushReaction() == PushReaction.BLOCK; + } + + @Override + public boolean isTicksRandomly() { + return block.isRandomlyTicking(blockState); + } + + @Override + public boolean isMovementBlocker() { + return craftMaterial.isSolid(); + } + + @Override + public boolean isBurnable() { + return craftMaterial.isBurnable(); + } + + @Override + public boolean isToolRequired() { + // Removed in 1.16.1, this is not present in higher versions + return false; + } + + @Override + public boolean isReplacedDuringPlacement() { + return blockState.canBeReplaced(); + } + + @Override + public boolean isTranslucent() { + return isTranslucent; + } + + @Override + public boolean hasContainer() { + return block instanceof EntityBlock; + } + + @Override + public boolean isTile() { + return block instanceof EntityBlock; + } + + @Override + public CompoundTag getDefaultTile() { + return tile; + } + + @Override + public int getMapColor() { + // rgb field + return block.defaultMapColor().col; + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java new file mode 100644 index 000000000..4414719b8 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java @@ -0,0 +1,617 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; + +import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; +import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; +import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.entity.LazyBaseEntity; +import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; +import com.fastasyncworldedit.core.queue.IBatchProcessor; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; +import com.fastasyncworldedit.core.util.NbtUtils; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.regen.PaperweightRegen; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +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.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.nbt.BinaryTag; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import com.sk89q.worldedit.util.nbt.StringBinaryTag; +import com.sk89q.worldedit.world.RegenOptions; +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.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import io.papermc.lib.PaperLib; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Registry; +import net.minecraft.core.WritableRegistry; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.StringRepresentable; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.chunk.LevelChunk; +import org.apache.logging.log4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.World; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_20_R3.CraftServer; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey; +import org.bukkit.entity.Player; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.OptionalInt; +import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static net.minecraft.core.registries.Registries.BIOME; + +public final class PaperweightFaweAdapter extends FaweAdapter { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; + + static { + try { + CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE = ChunkHolder.class.getDeclaredMethod("wasAccessibleSinceLastSave"); + } catch (NoSuchMethodException ignored) { // may not be present in newer paper versions + } + } + + private final com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3.PaperweightAdapter parent; + // ------------------------------------------------------------------------ + // Code that may break between versions of Minecraft + // ------------------------------------------------------------------------ + private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil(); + private char[] ibdToStateOrdinal = null; + private int[] ordinalToIbdID = null; + private boolean initialised = false; + private Map>> allBlockProperties = null; + + public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { + this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3.PaperweightAdapter(); + } + + @Nullable + private static String getEntityId(Entity entity) { + ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType()); + return resourceLocation == null ? null : resourceLocation.toString(); + } + + private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { + entity.save(compoundTag); + } + + @Override + public BukkitImplAdapter getParent() { + return parent; + } + + private synchronized boolean init() { + if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) { + return false; + } + ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size + ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size + for (int i = 0; i < ibdToStateOrdinal.length; i++) { + BlockState blockState = BlockTypesCache.states[i]; + PaperweightBlockMaterial material = (PaperweightBlockMaterial) blockState.getMaterial(); + int id = Block.BLOCK_STATE_REGISTRY.getId(material.getState()); + char ordinal = blockState.getOrdinalChar(); + ibdToStateOrdinal[id] = ordinal; + ordinalToIbdID[ordinal] = id; + } + Map>> properties = new HashMap<>(); + try { + for (Field field : BlockStateProperties.class.getDeclaredFields()) { + Object obj = field.get(null); + if (!(obj instanceof net.minecraft.world.level.block.state.properties.Property state)) { + continue; + } + Property property; + if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + property = new BooleanProperty( + state.getName(), + (List) ImmutableList.copyOf(state.getPossibleValues()) + ); + } else if (state instanceof DirectionProperty) { + property = new DirectionalProperty( + state.getName(), + state + .getPossibleValues() + .stream() + .map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase())) + .collect(Collectors.toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + property = new EnumProperty( + state.getName(), + state + .getPossibleValues() + .stream() + .map(e -> ((StringRepresentable) e).getSerializedName()) + .collect(Collectors.toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + property = new IntegerProperty( + state.getName(), + (List) ImmutableList.copyOf(state.getPossibleValues()) + ); + } else { + throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state + .getClass() + .getSimpleName()); + } + properties.compute(property.getName().toLowerCase(Locale.ROOT), (k, v) -> { + if (v == null) { + v = new ArrayList<>(Collections.singletonList(property)); + } else { + v.add(property); + } + return v; + }); + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } finally { + allBlockProperties = ImmutableMap.copyOf(properties); + } + initialised = true; + return true; + } + + @Override + public BlockMaterial getMaterial(BlockType blockType) { + Block block = getBlock(blockType); + return new PaperweightBlockMaterial(block); + } + + @Override + public synchronized BlockMaterial getMaterial(BlockState state) { + net.minecraft.world.level.block.state.BlockState blockState = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState(); + return new PaperweightBlockMaterial(blockState.getBlock(), blockState); + } + + public Block getBlock(BlockType blockType) { + return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK) + .get(new ResourceLocation(blockType.getNamespace(), blockType.getResource())); + } + + @Deprecated + @Override + public BlockState getBlock(Location location) { + Preconditions.checkNotNull(location); + + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + final ServerLevel handle = getServerLevel(location.getWorld()); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); + BlockState state = adapt(blockData); + if (state == null) { + org.bukkit.block.Block bukkitBlock = location.getBlock(); + state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } + return state; + } + + @Override + public BaseBlock getFullBlock(final Location location) { + Preconditions.checkNotNull(location); + + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = getServerLevel(location.getWorld()); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); + BlockState state = adapt(blockData); + if (state == null) { + org.bukkit.block.Block bukkitBlock = location.getBlock(); + state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } + if (state.getBlockType().getMaterial().hasContainer()) { + + // Read the NBT data + BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); + if (blockEntity != null) { + net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); + return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); + } + } + + return state.toBaseBlock(); + } + + @Override + public Set getSupportedSideEffects() { + return SideEffectSet.defaults().getSideEffectsToApply(); + } + + @Override + public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); + } + + @Override + public BaseEntity getEntity(org.bukkit.entity.Entity entity) { + Preconditions.checkNotNull(entity); + + CraftEntity craftEntity = ((CraftEntity) entity); + Entity mcEntity = craftEntity.getHandle(); + + String id = getEntityId(mcEntity); + + if (id != null) { + EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); + Supplier saveTag = () -> { + final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); + readEntityIntoTag(mcEntity, minecraftTag); + //add Id for AbstractChangeSet to work + final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); + final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); + tags.put("Id", StringBinaryTag.of(id)); + return CompoundBinaryTag.from(tags); + }; + return new LazyBaseEntity(type, saveTag); + } else { + return null; + } + } + + @Override + public Component getRichBlockName(BlockType blockType) { + return parent.getRichBlockName(blockType); + } + + @Override + public Component getRichItemName(ItemType itemType) { + return parent.getRichItemName(itemType); + } + + @Override + public Component getRichItemName(BaseItemStack itemStack) { + return parent.getRichItemName(itemStack); + } + + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); + net.minecraft.world.level.block.state.BlockState mcState = material.getCraftBlockData().getState(); + return OptionalInt.of(Block.BLOCK_STATE_REGISTRY.getId(mcState)); + } + + @Override + public BlockState adapt(BlockData blockData) { + CraftBlockData cbd = ((CraftBlockData) blockData); + net.minecraft.world.level.block.state.BlockState ibd = cbd.getState(); + return adapt(ibd); + } + + public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) { + return BlockTypesCache.states[adaptToChar(blockState)]; + } + + public char adaptToChar(net.minecraft.world.level.block.state.BlockState blockState) { + int id = Block.BLOCK_STATE_REGISTRY.getId(blockState); + if (initialised) { + return ibdToStateOrdinal[id]; + } + synchronized (this) { + if (initialised) { + return ibdToStateOrdinal[id]; + } + try { + init(); + return ibdToStateOrdinal[id]; + } catch (ArrayIndexOutOfBoundsException e1) { + LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!", + blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1 + ); + return BlockTypesCache.ReservedIDs.AIR; + } + } + } + + public char ibdIDToOrdinal(int id) { + if (initialised) { + return ibdToStateOrdinal[id]; + } + synchronized (this) { + if (initialised) { + return ibdToStateOrdinal[id]; + } + init(); + return ibdToStateOrdinal[id]; + } + } + + @Override + public char[] getIbdToStateOrdinal() { + if (initialised) { + return ibdToStateOrdinal; + } + synchronized (this) { + if (initialised) { + return ibdToStateOrdinal; + } + init(); + return ibdToStateOrdinal; + } + } + + public int ordinalToIbdID(char ordinal) { + if (initialised) { + return ordinalToIbdID[ordinal]; + } + synchronized (this) { + if (initialised) { + return ordinalToIbdID[ordinal]; + } + init(); + return ordinalToIbdID[ordinal]; + } + } + + @Override + public int[] getOrdinalToIbdID() { + if (initialised) { + return ordinalToIbdID; + } + synchronized (this) { + if (initialised) { + return ordinalToIbdID; + } + init(); + return ordinalToIbdID; + } + } + + @Override + public > BlockData adapt(B state) { + PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); + return material.getCraftBlockData(); + } + + @Override + public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { + ServerLevel nmsWorld = getServerLevel(world); + ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); + if (map != null && wasAccessibleSinceLastSave(map)) { + boolean flag = false; + // PlayerChunk.d players = map.players; + Stream stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag) + */ Stream.empty(); + + ServerPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle(); + stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer) + .forEach(entityPlayer -> { + synchronized (chunkPacket) { + ClientboundLevelChunkWithLightPacket nmsPacket = (ClientboundLevelChunkWithLightPacket) chunkPacket.getNativePacket(); + if (nmsPacket == null) { + nmsPacket = mapUtil.create(this, chunkPacket); + chunkPacket.setNativePacket(nmsPacket); + } + try { + FaweCache.INSTANCE.CHUNK_FLAG.get().set(true); + entityPlayer.connection.send(nmsPacket); + } finally { + FaweCache.INSTANCE.CHUNK_FLAG.get().set(false); + } + } + }); + } + } + + @Override + public Map> getProperties(BlockType blockType) { + return getParent().getProperties(blockType); + } + + @Override + public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) { + int internalId = BlockStateIdAccess.getBlockStateId(blockState); + net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); + return blockState1.hasPostProcess( + getServerLevel(world), + new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) + ); + } + + @Override + public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { + ItemStack stack = new ItemStack( + DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM) + .get(ResourceLocation.tryParse(baseItemStack.getType().getId())), + baseItemStack.getAmount() + ); + stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()))); + return CraftItemStack.asCraftMirror(stack); + } + + @Override + protected void preCaptureStates(final ServerLevel serverLevel) { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + } + + @Override + protected List getCapturedBlockStatesCopy(final ServerLevel serverLevel) { + return new ArrayList<>(serverLevel.capturedBlockStates.values()); + } + + @Override + protected void postCaptureBlockStates(final ServerLevel serverLevel) { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + + @Override + protected ServerLevel getServerLevel(final World world) { + return ((CraftWorld) world).getHandle(); + } + + @Override + public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { + final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); + final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); + weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); + return weStack; + } + + @Override + public Tag toNative(net.minecraft.nbt.Tag foreign) { + return parent.toNative(foreign); + } + + @Override + public net.minecraft.nbt.Tag fromNative(Tag foreign) { + if (foreign instanceof PaperweightLazyCompoundTag) { + return ((PaperweightLazyCompoundTag) foreign).get(); + } + return parent.fromNative(foreign); + } + + @Override + public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { + return new PaperweightRegen(bukkitWorld, region, target, options).regenerate(); + } + + @Override + public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { + return new PaperweightGetBlocks(world, chunkX, chunkZ); + } + + @Override + public int getInternalBiomeId(BiomeType biomeType) { + final Registry registry = MinecraftServer + .getServer() + .registryAccess() + .registryOrThrow(BIOME); + ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.getId()); + Biome biome = registry.get(resourceLocation); + return registry.getId(biome); + } + + @Override + public Iterable getRegisteredBiomes() { + WritableRegistry biomeRegistry = (WritableRegistry) ((CraftServer) Bukkit.getServer()) + .getServer() + .registryAccess() + .registryOrThrow(BIOME); + List keys = biomeRegistry.stream() + .map(biomeRegistry::getKey).filter(Objects::nonNull).toList(); + List namespacedKeys = new ArrayList<>(); + for (ResourceLocation key : keys) { + try { + namespacedKeys.add(CraftNamespacedKey.fromMinecraft(key)); + } catch (IllegalArgumentException e) { + LOGGER.error("Error converting biome key {}", key.toString(), e); + } + } + return namespacedKeys; + } + + @Override + public RelighterFactory getRelighterFactory() { + if (PaperLib.isPaper()) { + return new PaperweightStarlightRelighterFactory(); + } else { + return new NMSRelighterFactory(); + } + } + + @Override + public Map>> getAllProperties() { + if (initialised) { + return allBlockProperties; + } + synchronized (this) { + if (initialised) { + return allBlockProperties; + } + init(); + return allBlockProperties; + } + } + + @Override + public IBatchProcessor getTickingPostProcessor() { + return new PaperweightPostProcessor(); + } + + private boolean wasAccessibleSinceLastSave(ChunkHolder holder) { + if (!PaperLib.isPaper() || !PaperweightPlatformAdapter.POST_CHUNK_REWRITE) { + try { + return (boolean) CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE.invoke(holder); + } catch (IllegalAccessException | InvocationTargetException ignored) { + // fall-through + } + } + // Papers new chunk system has no related replacement - therefor we assume true. + return true; + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweWorldNativeAccess.java new file mode 100644 index 000000000..ad04e7b03 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweWorldNativeAccess.java @@ -0,0 +1,286 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; + +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.math.IntPair; +import com.fastasyncworldedit.core.util.TaskManager; +import com.fastasyncworldedit.core.util.task.RunnableVal; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import com.sk89q.worldedit.world.block.BlockState; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.FullChunkStatus; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; +import org.bukkit.event.block.BlockPhysicsEvent; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess { + + private static final int UPDATE = 1; + private static final int NOTIFY = 2; + private static final Direction[] NEIGHBOUR_ORDER = { + Direction.EAST, + Direction.WEST, + Direction.DOWN, + Direction.UP, + Direction.NORTH, + Direction.SOUTH + }; + private final PaperweightFaweAdapter paperweightFaweAdapter; + private final WeakReference level; + private final AtomicInteger lastTick; + private final Set cachedChanges = new HashSet<>(); + private final Set cachedChunksToSend = new HashSet<>(); + private SideEffectSet sideEffectSet; + + public PaperweightFaweWorldNativeAccess(PaperweightFaweAdapter paperweightFaweAdapter, WeakReference level) { + this.paperweightFaweAdapter = paperweightFaweAdapter; + this.level = level; + // Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging. + // - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway. + this.lastTick = new AtomicInteger(MinecraftServer.currentTick); + } + + private Level getLevel() { + return Objects.requireNonNull(level.get(), "The reference to the world was lost"); + } + + @Override + public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + @Override + public LevelChunk getChunk(int x, int z) { + return getLevel().getChunk(x, z); + } + + @Override + public net.minecraft.world.level.block.state.BlockState toNative(BlockState blockState) { + int stateId = paperweightFaweAdapter.ordinalToIbdID(blockState.getOrdinalChar()); + return BlockStateIdAccess.isValidInternalId(stateId) + ? Block.stateById(stateId) + : ((CraftBlockData) BukkitAdapter.adapt(blockState)).getState(); + } + + @Override + public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk levelChunk, BlockPos blockPos) { + return levelChunk.getBlockState(blockPos); + } + + @Nullable + @Override + public synchronized net.minecraft.world.level.block.state.BlockState setBlockState( + LevelChunk levelChunk, BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState blockState + ) { + int currentTick = MinecraftServer.currentTick; + if (Fawe.isMainThread()) { + return levelChunk.setBlockState(blockPos, blockState, + this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE) + ); + } + // Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( ) + cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState)); + cachedChunksToSend.add(new IntPair(levelChunk.locX, levelChunk.locZ)); + boolean nextTick = lastTick.get() > currentTick; + if (nextTick || cachedChanges.size() >= 1024) { + if (nextTick) { + lastTick.set(currentTick); + } + flushAsync(nextTick); + } + return blockState; + } + + @Override + public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition( + net.minecraft.world.level.block.state.BlockState blockState, + BlockPos blockPos + ) { + return Block.updateFromNeighbourShapes(blockState, getLevel(), blockPos); + } + + @Override + public BlockPos getPosition(int x, int y, int z) { + return new BlockPos(x, y, z); + } + + @Override + public void updateLightingForBlock(BlockPos blockPos) { + getLevel().getChunkSource().getLightEngine().checkBlock(blockPos); + } + + @Override + public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) { + // We will assume that the tile entity was created for us, + // though we do not do this on the other versions + BlockEntity blockEntity = getLevel().getBlockEntity(blockPos); + if (blockEntity == null) { + return false; + } + net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeBinary(tag); + blockEntity.load((CompoundTag) nativeTag); + return true; + } + + @Override + public void notifyBlockUpdate( + LevelChunk levelChunk, BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { + getLevel().sendBlockUpdated(blockPos, oldState, newState, UPDATE | NOTIFY); + } + } + + @Override + public boolean isChunkTicking(LevelChunk levelChunk) { + return levelChunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING); + } + + @Override + public void markBlockChanged(LevelChunk levelChunk, BlockPos blockPos) { + if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { + ((ServerChunkCache) getLevel().getChunkSource()).blockChanged(blockPos); + } + } + + @Override + public void notifyNeighbors( + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + Level level = getLevel(); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + level.blockUpdated(blockPos, oldState.getBlock()); + } else { + // When we don't want events, manually run the physics without them. + // Un-nest neighbour updating + for (Direction direction : NEIGHBOUR_ORDER) { + BlockPos shifted = blockPos.relative(direction); + level.getBlockState(shifted).neighborChanged(level, shifted, oldState.getBlock(), blockPos, false); + } + } + if (newState.hasAnalogOutputSignal()) { + level.updateNeighbourForOutputSignal(blockPos, newState.getBlock()); + } + } + + @Override + public void updateNeighbors( + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState, + int recursionLimit + ) { + Level level = getLevel(); + // a == updateNeighbors + // b == updateDiagonalNeighbors + oldState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + CraftWorld craftWorld = level.getWorld(); + if (craftWorld != null) { + BlockPhysicsEvent event = new BlockPhysicsEvent( + craftWorld.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()), + CraftBlockData.fromData(newState) + ); + level.getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + } + } + newState.triggerEvent(level, blockPos, NOTIFY, recursionLimit); + newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); + } + + @Override + public void onBlockStateChange( + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + getLevel().onBlockStateChange(blockPos, oldState, newState); + } + + private synchronized void flushAsync(final boolean sendChunks) { + final Set changes = Set.copyOf(cachedChanges); + cachedChanges.clear(); + final Set toSend; + if (sendChunks) { + toSend = Set.copyOf(cachedChunksToSend); + cachedChunksToSend.clear(); + } else { + toSend = Collections.emptySet(); + } + RunnableVal runnableVal = new RunnableVal<>() { + @Override + public void run(Object value) { + changes.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, + sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) + )); + if (!sendChunks) { + return; + } + for (IntPair chunk : toSend) { + PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); + } + } + }; + TaskManager.taskManager().async(() -> TaskManager.taskManager().sync(runnableVal)); + } + + @Override + public synchronized void flush() { + RunnableVal runnableVal = new RunnableVal<>() { + @Override + public void run(Object value) { + cachedChanges.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, + sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) + )); + for (IntPair chunk : cachedChunksToSend) { + PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); + } + } + }; + if (Fawe.isMainThread()) { + runnableVal.run(); + } else { + TaskManager.taskManager().sync(runnableVal); + } + cachedChanges.clear(); + cachedChunksToSend.clear(); + } + + private record CachedChange( + LevelChunk levelChunk, + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState blockState + ) { + + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java new file mode 100644 index 000000000..8139adc87 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java @@ -0,0 +1,1181 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; + +import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; +import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import com.fastasyncworldedit.core.queue.implementation.QueueHandler; +import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; +import com.fastasyncworldedit.core.util.MathMan; +import com.fastasyncworldedit.core.util.collection.AdaptedMap; +import com.google.common.base.Suppliers; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import io.papermc.lib.PaperLib; +import io.papermc.paper.event.block.BeaconDeactivatedEvent; +import net.minecraft.core.*; +import net.minecraft.nbt.IntTag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.util.BitStorage; +import net.minecraft.util.ZeroBitStorage; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.entity.BeaconBlockEntity; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.*; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.apache.logging.log4j.Logger; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import javax.annotation.Nonnull; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Future; +import java.util.concurrent.Semaphore; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static net.minecraft.core.registries.Registries.BIOME; + +public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private static final Function posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); + private static final Function nmsTile2We = + tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); + private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin + .getInstance() + .getBukkitImplAdapter()); + private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); + private final ReentrantLock callLock = new ReentrantLock(); + private final ServerLevel serverLevel; + private final int chunkX; + private final int chunkZ; + private final int minHeight; + private final int maxHeight; + private final int minSectionPosition; + private final int maxSectionPosition; + private final Registry biomeRegistry; + private final IdMap> biomeHolderIdMap; + private final ConcurrentHashMap copies = new ConcurrentHashMap<>(); + private final Object sendLock = new Object(); + private LevelChunkSection[] sections; + private LevelChunk levelChunk; + private DataLayer[] blockLight; + private DataLayer[] skyLight; + private boolean createCopy = false; + private boolean forceLoadSections = true; + private boolean lightUpdate = false; + private int copyKey = 0; + + public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { + this(((CraftWorld) world).getHandle(), chunkX, chunkZ); + } + + public PaperweightGetBlocks(ServerLevel serverLevel, int chunkX, int chunkZ) { + super(serverLevel.getMinBuildHeight() >> 4, (serverLevel.getMaxBuildHeight() - 1) >> 4); + this.serverLevel = serverLevel; + this.chunkX = chunkX; + this.chunkZ = chunkZ; + this.minHeight = serverLevel.getMinBuildHeight(); + this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. + this.minSectionPosition = minHeight >> 4; + this.maxSectionPosition = maxHeight >> 4; + this.skyLight = new DataLayer[getSectionCount()]; + this.blockLight = new DataLayer[getSectionCount()]; + this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME); + this.biomeHolderIdMap = biomeRegistry.asHolderIdMap(); + } + + public int getChunkX() { + return chunkX; + } + + public int getChunkZ() { + return chunkZ; + } + + @Override + public boolean isCreateCopy() { + return createCopy; + } + + @Override + public int setCreateCopy(boolean createCopy) { + if (!callLock.isHeldByCurrentThread()) { + throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); + } + this.createCopy = createCopy; + return ++this.copyKey; + } + + @Override + public IChunkGet getCopy(final int key) { + return copies.remove(key); + } + + @Override + public void lockCall() { + this.callLock.lock(); + } + + @Override + public void unlockCall() { + this.callLock.unlock(); + } + + @Override + public void setLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { + if (light != null) { + lightUpdate = true; + try { + fillLightNibble(light, LightLayer.BLOCK, minSectionPosition, maxSectionPosition); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + @Override + public void setSkyLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { + if (light != null) { + lightUpdate = true; + try { + fillLightNibble(light, LightLayer.SKY, minSectionPosition, maxSectionPosition); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + @Override + public void setHeightmapToGet(HeightMapType type, int[] data) { + // height + 1 to match server internal + BitArrayUnstretched bitArray = new BitArrayUnstretched(MathMan.log2nlz(getChunk().getHeight() + 1), 256); + bitArray.fromRaw(data); + Heightmap.Types nativeType = Heightmap.Types.valueOf(type.name()); + Heightmap heightMap = getChunk().heightmaps.get(nativeType); + heightMap.setRawData(getChunk(), nativeType, bitArray.getData()); + } + + @Override + public int getMaxY() { + return maxHeight; + } + + @Override + public int getMinY() { + return minHeight; + } + + @Override + public BiomeType getBiomeType(int x, int y, int z) { + LevelChunkSection section = getSections(false)[(y >> 4) - getMinSectionPosition()]; + Holder biomes = section.getNoiseBiome(x >> 2, (y & 15) >> 2, z >> 2); + return PaperweightPlatformAdapter.adapt(biomes, serverLevel); + } + + @Override + public void removeSectionLighting(int layer, boolean sky) { + SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.BLOCK).getDataLayerData( + sectionPos); + if (dataLayer != null) { + lightUpdate = true; + synchronized (dataLayer) { + byte[] bytes = dataLayer.getData(); + Arrays.fill(bytes, (byte) 0); + } + } + if (sky) { + SectionPos sectionPos1 = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer1 = serverLevel + .getChunkSource() + .getLightEngine() + .getLayerListener(LightLayer.SKY) + .getDataLayerData(sectionPos1); + if (dataLayer1 != null) { + lightUpdate = true; + synchronized (dataLayer1) { + byte[] bytes = dataLayer1.getData(); + Arrays.fill(bytes, (byte) 0); + } + } + } + } + + @Override + public CompoundTag getTile(int x, int y, int z) { + BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( + chunkX << 4), y, (z & 15) + ( + chunkZ << 4))); + if (blockEntity == null) { + return null; + } + return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)); + } + + @Override + public Map getTiles() { + Map nmsTiles = getChunk().getBlockEntities(); + if (nmsTiles.isEmpty()) { + return Collections.emptyMap(); + } + return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); + } + + @Override + public int getSkyLight(int x, int y, int z) { + int layer = y >> 4; + int alayer = layer - getMinSectionPosition(); + if (skyLight[alayer] == null) { + SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer = + serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.SKY).getDataLayerData(sectionPos); + // If the server hasn't generated the section's NibbleArray yet, it will be null + if (dataLayer == null) { + byte[] LAYER_COUNT = new byte[2048]; + // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. + Arrays.fill(LAYER_COUNT, (byte) 15); + dataLayer = new DataLayer(LAYER_COUNT); + ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( + LightLayer.BLOCK, + sectionPos, + dataLayer + ); + } + skyLight[alayer] = dataLayer; + } + return skyLight[alayer].get(x & 15, y & 15, z & 15); + } + + @Override + public int getEmittedLight(int x, int y, int z) { + int layer = y >> 4; + int alayer = layer - getMinSectionPosition(); + if (blockLight[alayer] == null) { + serverLevel.getRawBrightness(new BlockPos(1, 1, 1), 5); + SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer = serverLevel + .getChunkSource() + .getLightEngine() + .getLayerListener(LightLayer.BLOCK) + .getDataLayerData(sectionPos); + // If the server hasn't generated the section's DataLayer yet, it will be null + if (dataLayer == null) { + byte[] LAYER_COUNT = new byte[2048]; + // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. + Arrays.fill(LAYER_COUNT, (byte) 15); + dataLayer = new DataLayer(LAYER_COUNT); + ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos, + dataLayer + ); + } + blockLight[alayer] = dataLayer; + } + return blockLight[alayer].get(x & 15, y & 15, z & 15); + } + + @Override + public int[] getHeightMap(HeightMapType type) { + long[] longArray = getChunk().heightmaps.get(Heightmap.Types.valueOf(type.name())).getRawData(); + BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256, longArray); + return bitArray.toRaw(new int[256]); + } + + @Override + public CompoundTag getEntity(UUID uuid) { + ensureLoaded(serverLevel, chunkX, chunkZ); + List entities = PaperweightPlatformAdapter.getEntities(getChunk()); + Entity entity = null; + for (Entity e : entities) { + if (e.getUUID().equals(uuid)) { + entity = e; + break; + } + } + if (entity != null) { + org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); + return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); + } + for (CompoundTag tag : getEntities()) { + if (uuid.equals(tag.getUUID())) { + return tag; + } + } + return null; + } + + @Override + public Set getEntities() { + ensureLoaded(serverLevel, chunkX, chunkZ); + List entities = PaperweightPlatformAdapter.getEntities(getChunk()); + if (entities.isEmpty()) { + return Collections.emptySet(); + } + int size = entities.size(); + return new AbstractSet<>() { + @Override + public int size() { + return size; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean contains(Object get) { + if (!(get instanceof CompoundTag getTag)) { + return false; + } + UUID getUUID = getTag.getUUID(); + for (Entity entity : entities) { + UUID uuid = entity.getUUID(); + if (uuid.equals(getUUID)) { + return true; + } + } + return false; + } + + @Nonnull + @Override + public Iterator iterator() { + Iterable result = entities.stream().map(input -> { + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + input.save(tag); + return (CompoundTag) adapter.toNative(tag); + }).collect(Collectors.toList()); + return result.iterator(); + } + }; + } + + private void removeEntity(Entity entity) { + entity.discard(); + } + + public LevelChunk ensureLoaded(ServerLevel nmsWorld, int chunkX, int chunkZ) { + return PaperweightPlatformAdapter.ensureLoaded(nmsWorld, chunkX, chunkZ); + } + + @Override + @SuppressWarnings("rawtypes") + public synchronized > T call(IChunkSet set, Runnable finalizer) { + if (!callLock.isHeldByCurrentThread()) { + throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked."); + } + forceLoadSections = false; + PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + if (createCopy) { + if (copies.containsKey(copyKey)) { + throw new IllegalStateException("Copy key already used."); + } + copies.put(copyKey, copy); + } + try { + ServerLevel nmsWorld = serverLevel; + LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); + + // Remove existing tiles. Create a copy so that we can remove blocks + Map chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); + List beacons = null; + if (!chunkTiles.isEmpty()) { + for (Map.Entry entry : chunkTiles.entrySet()) { + final BlockPos pos = entry.getKey(); + final int lx = pos.getX() & 15; + final int ly = pos.getY(); + final int lz = pos.getZ() & 15; + final int layer = ly >> 4; + if (!set.hasSection(layer)) { + continue; + } + + int ordinal = set.getBlock(lx, ly, lz).getOrdinal(); + if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) { + BlockEntity tile = entry.getValue(); + if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) { + if (beacons == null) { + beacons = new ArrayList<>(); + } + beacons.add(tile); + PaperweightPlatformAdapter.removeBeacon(tile, nmsChunk); + continue; + } + nmsChunk.removeBlockEntity(tile.getBlockPos()); + if (createCopy) { + copy.storeTile(tile); + } + } + } + } + final BiomeType[][] biomes = set.getBiomes(); + + int bitMask = 0; + synchronized (nmsChunk) { + LevelChunkSection[] levelChunkSections = nmsChunk.getSections(); + + for (int layerNo = getMinSectionPosition(); layerNo <= getMaxSectionPosition(); layerNo++) { + + int getSectionIndex = layerNo - getMinSectionPosition(); + int setSectionIndex = layerNo - set.getMinSectionPosition(); + + if (!set.hasSection(layerNo)) { + // No blocks, but might be biomes present. Handle this lazily. + if (biomes == null) { + continue; + } + if (layerNo < set.getMinSectionPosition() || layerNo > set.getMaxSectionPosition()) { + continue; + } + if (biomes[setSectionIndex] != null) { + synchronized (super.sectionLocks[getSectionIndex]) { + LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; + if (createCopy && existingSection != null) { + copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); + } + + if (existingSection == null) { + PalettedContainer> biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer( + biomes[setSectionIndex], + biomeHolderIdMap + ); + LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + new char[4096], + adapter, + biomeRegistry, + biomeData + ); + if (PaperweightPlatformAdapter.setSectionAtomic( + levelChunkSections, + null, + newSection, + getSectionIndex + )) { + updateGet(nmsChunk, levelChunkSections, newSection, new char[4096], getSectionIndex); + continue; + } else { + existingSection = levelChunkSections[getSectionIndex]; + if (existingSection == null) { + LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, + getSectionIndex + ); + continue; + } + } + } else { + setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); + } + } + } + continue; + } + + bitMask |= 1 << getSectionIndex; + + // setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to + // this chunk GET when #updateGet is called. Future dords, please listen this time. + char[] tmp = set.load(layerNo); + char[] setArr = new char[tmp.length]; + System.arraycopy(tmp, 0, setArr, 0, tmp.length); + + // synchronise on internal section to avoid circular locking with a continuing edit if the chunk was + // submitted to keep loaded internal chunks to queue target size. + synchronized (super.sectionLocks[getSectionIndex]) { + + LevelChunkSection newSection; + LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; + // Don't attempt to tick section whilst we're editing + if (existingSection != null) { + PaperweightPlatformAdapter.clearCounts(existingSection); + if (PaperLib.isPaper()) { + existingSection.tickingList.clear(); + } + } + + if (createCopy) { + char[] tmpLoad = loadPrivately(layerNo); + char[] copyArr = new char[4096]; + System.arraycopy(tmpLoad, 0, copyArr, 0, 4096); + copy.storeSection(getSectionIndex, copyArr); + if (biomes != null && existingSection != null) { + copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); + } + } + + if (existingSection == null) { + PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( + biomeHolderIdMap, + biomeHolderIdMap.byIdOrThrow(WorldEditPlugin + .getInstance() + .getBukkitImplAdapter() + .getInternalBiomeId( + BiomeTypes.PLAINS)), + PalettedContainer.Strategy.SECTION_BIOMES + ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + setArr, + adapter, + biomeRegistry, + biomeData + ); + if (PaperweightPlatformAdapter.setSectionAtomic( + levelChunkSections, + null, + newSection, + getSectionIndex + )) { + updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); + continue; + } else { + existingSection = levelChunkSections[getSectionIndex]; + if (existingSection == null) { + LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, + getSectionIndex + ); + continue; + } + } + } + + //ensure that the server doesn't try to tick the chunksection while we're editing it. (Again) + PaperweightPlatformAdapter.clearCounts(existingSection); + if (PaperLib.isPaper()) { + existingSection.tickingList.clear(); + } + DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); + + // Synchronize to prevent further acquisitions + synchronized (lock) { + lock.acquire(); // Wait until we have the lock + lock.release(); + try { + sectionLock.writeLock().lock(); + if (this.getChunk() != nmsChunk) { + this.levelChunk = nmsChunk; + this.sections = null; + this.reset(); + } else if (existingSection != getSections(false)[getSectionIndex]) { + this.sections[getSectionIndex] = existingSection; + this.reset(); + } else if (!Arrays.equals( + update(getSectionIndex, new char[4096], true), + loadPrivately(layerNo) + )) { + this.reset(layerNo); + /*} else if (lock.isModified()) { + this.reset(layerNo);*/ + } + } finally { + sectionLock.writeLock().unlock(); + } + + PalettedContainer> biomeData = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); + + newSection = + PaperweightPlatformAdapter.newChunkSection( + layerNo, + this::loadPrivately, + setArr, + adapter, + biomeRegistry, + biomeData + ); + if (!PaperweightPlatformAdapter.setSectionAtomic( + levelChunkSections, + existingSection, + newSection, + getSectionIndex + )) { + LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, + getSectionIndex + ); + } else { + updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); + } + } + } + } + + Map heightMaps = set.getHeightMaps(); + for (Map.Entry entry : heightMaps.entrySet()) { + PaperweightGetBlocks.this.setHeightmapToGet(entry.getKey(), entry.getValue()); + } + PaperweightGetBlocks.this.setLightingToGet( + set.getLight(), + set.getMinSectionPosition(), + set.getMaxSectionPosition() + ); + PaperweightGetBlocks.this.setSkyLightingToGet( + set.getSkyLight(), + set.getMinSectionPosition(), + set.getMaxSectionPosition() + ); + + Runnable[] syncTasks = null; + + int bx = chunkX << 4; + int bz = chunkZ << 4; + + // Call beacon deactivate events here synchronously + // list will be null on spigot, so this is an implicit isPaper check + if (beacons != null && !beacons.isEmpty()) { + final List finalBeacons = beacons; + + syncTasks = new Runnable[4]; + + syncTasks[3] = () -> { + for (BlockEntity beacon : finalBeacons) { + BeaconBlockEntity.playSound(beacon.getLevel(), beacon.getBlockPos(), SoundEvents.BEACON_DEACTIVATE); + new BeaconDeactivatedEvent(CraftBlock.at(beacon.getLevel(), beacon.getBlockPos())).callEvent(); + } + }; + } + + Set entityRemoves = set.getEntityRemoves(); + if (entityRemoves != null && !entityRemoves.isEmpty()) { + if (syncTasks == null) { + syncTasks = new Runnable[3]; + } + + syncTasks[2] = () -> { + Set entitiesRemoved = new HashSet<>(); + final List entities = PaperweightPlatformAdapter.getEntities(nmsChunk); + + for (Entity entity : entities) { + UUID uuid = entity.getUUID(); + if (entityRemoves.contains(uuid)) { + if (createCopy) { + copy.storeEntity(entity); + } + removeEntity(entity); + entitiesRemoved.add(uuid); + entityRemoves.remove(uuid); + } + } + if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { + for (UUID uuid : entityRemoves) { + Entity entity = nmsWorld.getEntities().get(uuid); + if (entity != null) { + removeEntity(entity); + } + } + } + // Only save entities that were actually removed to history + set.getEntityRemoves().clear(); + set.getEntityRemoves().addAll(entitiesRemoved); + }; + } + + Set entities = set.getEntities(); + if (entities != null && !entities.isEmpty()) { + if (syncTasks == null) { + syncTasks = new Runnable[2]; + } + + syncTasks[1] = () -> { + Iterator iterator = entities.iterator(); + while (iterator.hasNext()) { + final CompoundTag nativeTag = iterator.next(); + final Map entityTagMap = nativeTag.getValue(); + final StringTag idTag = (StringTag) entityTagMap.get("Id"); + final ListTag posTag = (ListTag) entityTagMap.get("Pos"); + final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); + if (idTag == null || posTag == null || rotTag == null) { + LOGGER.error("Unknown entity tag: {}", nativeTag); + continue; + } + final double x = posTag.getDouble(0); + final double y = posTag.getDouble(1); + final double z = posTag.getDouble(2); + final float yaw = rotTag.getFloat(0); + final float pitch = rotTag.getFloat(1); + final String id = idTag.getValue(); + + EntityType type = EntityType.byString(id).orElse(null); + if (type != null) { + Entity entity = type.create(nmsWorld); + if (entity != null) { + final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( + nativeTag); + for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + entity.load(tag); + entity.absMoveTo(x, y, z, yaw, pitch); + entity.setUUID(nativeTag.getUUID()); + if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { + LOGGER.warn( + "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", + id, + nmsWorld.getWorld().getName(), + x, + y, + z + ); + // Unsuccessful create should not be saved to history + iterator.remove(); + } + } + } + } + }; + } + + // set tiles + Map tiles = set.getTiles(); + if (tiles != null && !tiles.isEmpty()) { + if (syncTasks == null) { + syncTasks = new Runnable[1]; + } + + syncTasks[0] = () -> { + for (final Map.Entry entry : tiles.entrySet()) { + final CompoundTag nativeTag = entry.getValue(); + final BlockVector3 blockHash = entry.getKey(); + final int x = blockHash.getX() + bx; + final int y = blockHash.getY(); + final int z = blockHash.getZ() + bz; + final BlockPos pos = new BlockPos(x, y, z); + + synchronized (nmsWorld) { + BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); + if (tileEntity == null || tileEntity.isRemoved()) { + nmsWorld.removeBlockEntity(pos); + tileEntity = nmsWorld.getBlockEntity(pos); + } + if (tileEntity != null) { + final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( + nativeTag); + tag.put("x", IntTag.valueOf(x)); + tag.put("y", IntTag.valueOf(y)); + tag.put("z", IntTag.valueOf(z)); + tileEntity.load(tag); + } + } + } + }; + } + + Runnable callback; + if (bitMask == 0 && biomes == null && !lightUpdate) { + callback = null; + } else { + int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; + boolean finalLightUpdate = lightUpdate; + callback = () -> { + // Set Modified + nmsChunk.setLightCorrect(true); // Set Modified + nmsChunk.mustNotSave = false; + nmsChunk.setUnsaved(true); + // send to player + if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { + this.send(finalMask, finalLightUpdate); + } + if (finalizer != null) { + finalizer.run(); + } + }; + } + if (syncTasks != null) { + QueueHandler queueHandler = Fawe.instance().getQueueHandler(); + Runnable[] finalSyncTasks = syncTasks; + + // Chain the sync tasks and the callback + Callable chain = () -> { + try { + // Run the sync tasks + for (Runnable task : finalSyncTasks) { + if (task != null) { + task.run(); + } + } + if (callback == null) { + if (finalizer != null) { + finalizer.run(); + } + return null; + } else { + return queueHandler.async(callback, null); + } + } catch (Throwable e) { + e.printStackTrace(); + throw e; + } + }; + //noinspection unchecked - required at compile time + return (T) (Future) queueHandler.sync(chain); + } else { + if (callback == null) { + if (finalizer != null) { + finalizer.run(); + } + } else { + callback.run(); + } + } + } + return null; + } catch (Throwable e) { + e.printStackTrace(); + return null; + } finally { + forceLoadSections = true; + } + } + + private void updateGet( + LevelChunk nmsChunk, + LevelChunkSection[] chunkSections, + LevelChunkSection section, + char[] arr, + int layer + ) { + try { + sectionLock.writeLock().lock(); + if (this.getChunk() != nmsChunk) { + this.levelChunk = nmsChunk; + this.sections = new LevelChunkSection[chunkSections.length]; + System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); + this.reset(); + } + if (this.sections == null) { + this.sections = new LevelChunkSection[chunkSections.length]; + System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); + } + if (this.sections[layer] != section) { + // Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords + this.sections[layer] = new LevelChunkSection[]{section}.clone()[0]; + } + } finally { + sectionLock.writeLock().unlock(); + } + this.blocks[layer] = arr; + } + + private char[] loadPrivately(int layer) { + layer -= getMinSectionPosition(); + if (super.sections[layer] != null) { + synchronized (super.sectionLocks[layer]) { + if (super.sections[layer].isFull() && super.blocks[layer] != null) { + return super.blocks[layer]; + } + } + } + return PaperweightGetBlocks.this.update(layer, null, true); + } + + @Override + public void send(int mask, boolean lighting) { + synchronized (sendLock) { + PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); + } + } + + /** + * Update a given (nullable) data array to the current data stored in the server's chunk, associated with this + * {@link PaperweightPlatformAdapter} instance. Not synchronised to the {@link PaperweightPlatformAdapter} instance as synchronisation + * is handled where necessary in the method, and should otherwise be handled correctly by this method's caller. + * + * @param layer layer index (0 may denote a negative layer in the world, e.g. at y=-32) + * @param data array to be updated/filled with data or null + * @param aggressive if the cached section array should be re-acquired. + * @return the given array to be filled with data, or a new array if null is given. + */ + @Override + @SuppressWarnings("unchecked") + public char[] update(int layer, char[] data, boolean aggressive) { + LevelChunkSection section = getSections(aggressive)[layer]; + // Section is null, return empty array + if (section == null) { + data = new char[4096]; + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); + return data; + } + if (data != null && data.length != 4096) { + data = new char[4096]; + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); + } + if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) { + data = new char[4096]; + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); + } + Semaphore lock = PaperweightPlatformAdapter.applyLock(section); + synchronized (lock) { + // Efficiently convert ChunkSection to raw data + try { + lock.acquire(); + + final PalettedContainer blocks = section.getStates(); + final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocks); + final BitStorage bits = (BitStorage) PaperweightPlatformAdapter.fieldStorage.get(dataObject); + + if (bits instanceof ZeroBitStorage) { + Arrays.fill(data, adapter.adaptToChar(blocks.get(0, 0, 0))); // get(int) is only public on paper + return data; + } + + final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get(dataObject); + + final int bitsPerEntry = bits.getBits(); + final long[] blockStates = bits.getRaw(); + + new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).toRaw(data); + + int num_palette; + if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { + num_palette = palette.getSize(); + } else { + // The section's palette is the global block palette. + for (int i = 0; i < 4096; i++) { + char paletteVal = data[i]; + char ordinal = adapter.ibdIDToOrdinal(paletteVal); + data[i] = ordinal; + } + return data; + } + + char[] paletteToOrdinal = FaweCache.INSTANCE.PALETTE_TO_BLOCK_CHAR.get(); + try { + if (num_palette != 1) { + for (int i = 0; i < num_palette; i++) { + char ordinal = ordinal(palette.valueFor(i), adapter); + paletteToOrdinal[i] = ordinal; + } + for (int i = 0; i < 4096; i++) { + char paletteVal = data[i]; + char val = paletteToOrdinal[paletteVal]; + if (val == Character.MAX_VALUE) { + val = ordinal(palette.valueFor(i), adapter); + paletteToOrdinal[i] = val; + } + data[i] = val; + } + } else { + char ordinal = ordinal(palette.valueFor(0), adapter); + Arrays.fill(data, ordinal); + } + } finally { + for (int i = 0; i < num_palette; i++) { + paletteToOrdinal[i] = Character.MAX_VALUE; + } + } + return data; + } catch (IllegalAccessException | InterruptedException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } finally { + lock.release(); + } + } + } + + private char ordinal(BlockState ibd, PaperweightFaweAdapter adapter) { + if (ibd == null) { + return BlockTypesCache.ReservedIDs.AIR; + } else { + return adapter.adaptToChar(ibd); + } + } + + public LevelChunkSection[] getSections(boolean force) { + force &= forceLoadSections; + LevelChunkSection[] tmp = sections; + if (tmp == null || force) { + try { + sectionLock.writeLock().lock(); + tmp = sections; + if (tmp == null || force) { + LevelChunkSection[] chunkSections = getChunk().getSections(); + tmp = new LevelChunkSection[chunkSections.length]; + System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length); + sections = tmp; + } + } finally { + sectionLock.writeLock().unlock(); + } + } + return tmp; + } + + public LevelChunk getChunk() { + LevelChunk levelChunk = this.levelChunk; + if (levelChunk == null) { + synchronized (this) { + levelChunk = this.levelChunk; + if (levelChunk == null) { + this.levelChunk = levelChunk = ensureLoaded(this.serverLevel, chunkX, chunkZ); + } + } + } + return levelChunk; + } + + private void fillLightNibble(char[][] light, LightLayer lightLayer, int minSectionPosition, int maxSectionPosition) { + for (int Y = 0; Y <= maxSectionPosition - minSectionPosition; Y++) { + if (light[Y] == null) { + continue; + } + SectionPos sectionPos = SectionPos.of(levelChunk.getPos(), Y + minSectionPosition); + DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(lightLayer).getDataLayerData( + sectionPos); + if (dataLayer == null) { + byte[] LAYER_COUNT = new byte[2048]; + Arrays.fill(LAYER_COUNT, lightLayer == LightLayer.SKY ? (byte) 15 : (byte) 0); + dataLayer = new DataLayer(LAYER_COUNT); + ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( + lightLayer, + sectionPos, + dataLayer + ); + } + synchronized (dataLayer) { + for (int x = 0; x < 16; x++) { + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + int i = y << 8 | z << 4 | x; + if (light[Y][i] < 16) { + dataLayer.set(x, y, z, light[Y][i]); + } + } + } + } + } + } + } + + private PalettedContainer> setBiomesToPalettedContainer( + final BiomeType[][] biomes, + final int sectionIndex, + final PalettedContainerRO> data + ) { + PalettedContainer> biomeData; + if (data instanceof PalettedContainer> palettedContainer) { + biomeData = palettedContainer; + } else { + LOGGER.warn( + "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + + "type {} but got {}", + PalettedContainer.class.getSimpleName(), + data.getClass().getSimpleName() + ); + biomeData = data.recreate(); + } + BiomeType[] sectionBiomes; + if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { + return biomeData; + } + for (int y = 0, index = 0; y < 4; y++) { + for (int z = 0; z < 4; z++) { + for (int x = 0; x < 4; x++, index++) { + BiomeType biomeType = sectionBiomes[index]; + if (biomeType == null) { + continue; + } + biomeData.set( + x, + y, + z, + biomeHolderIdMap.byIdOrThrow(WorldEditPlugin + .getInstance() + .getBukkitImplAdapter() + .getInternalBiomeId(biomeType)) + ); + } + } + } + return biomeData; + } + + @Override + public boolean hasSection(int layer) { + layer -= getMinSectionPosition(); + return getSections(false)[layer] != null; + } + + @Override + @SuppressWarnings("unchecked") + public synchronized boolean trim(boolean aggressive) { + skyLight = new DataLayer[getSectionCount()]; + blockLight = new DataLayer[getSectionCount()]; + if (aggressive) { + sectionLock.writeLock().lock(); + sections = null; + levelChunk = null; + sectionLock.writeLock().unlock(); + return super.trim(true); + } else if (sections == null) { + // don't bother trimming if there are no sections stored. + return true; + } else { + for (int i = getMinSectionPosition(); i <= getMaxSectionPosition(); i++) { + int layer = i - getMinSectionPosition(); + if (!hasSection(i) || !super.sections[layer].isFull()) { + continue; + } + LevelChunkSection existing = getSections(true)[layer]; + try { + final PalettedContainer blocksExisting = existing.getStates(); + + final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocksExisting); + final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get( + dataObject); + int paletteSize; + + if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { + paletteSize = palette.getSize(); + } else { + super.trim(false, i); + continue; + } + if (paletteSize == 1) { + //If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks. + continue; + } + super.trim(false, i); + } catch (IllegalAccessException ignored) { + super.trim(false, i); + } + } + return true; + } + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java new file mode 100644 index 000000000..92d9ec801 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java @@ -0,0 +1,254 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; + +import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.queue.IBlocks; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import com.google.common.base.Suppliers; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.BlockVector3; +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.BlockTypesCache; +import net.minecraft.core.Holder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import org.apache.logging.log4j.Logger; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Future; + +public class PaperweightGetBlocks_Copy implements IChunkGet { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private final Map tiles = new HashMap<>(); + private final Set entities = new HashSet<>(); + private final char[][] blocks; + private final int minHeight; + private final int maxHeight; + final ServerLevel serverLevel; + final LevelChunk levelChunk; + private PalettedContainer>[] biomes = null; + + protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { + this.levelChunk = levelChunk; + this.serverLevel = levelChunk.level; + this.minHeight = serverLevel.getMinBuildHeight(); + this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. + this.blocks = new char[getSectionCount()][]; + } + + protected void storeTile(BlockEntity blockEntity) { + tiles.put( + BlockVector3.at( + blockEntity.getBlockPos().getX(), + blockEntity.getBlockPos().getY(), + blockEntity.getBlockPos().getZ() + ), + new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)) + ); + } + + @Override + public Map getTiles() { + return tiles; + } + + @Override + @Nullable + public CompoundTag getTile(int x, int y, int z) { + return tiles.get(BlockVector3.at(x, y, z)); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + protected void storeEntity(Entity entity) { + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); + entity.save(compoundTag); + entities.add((CompoundTag) adapter.toNative(compoundTag)); + } + + @Override + public Set getEntities() { + return this.entities; + } + + @Override + public CompoundTag getEntity(UUID uuid) { + for (CompoundTag tag : entities) { + if (uuid.equals(tag.getUUID())) { + return tag; + } + } + return null; + } + + @Override + public boolean isCreateCopy() { + return false; + } + + @Override + public int setCreateCopy(boolean createCopy) { + return -1; + } + + @Override + public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { + } + + @Override + public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { + } + + @Override + public void setHeightmapToGet(HeightMapType type, int[] data) { + } + + @Override + public int getMaxY() { + return maxHeight; + } + + @Override + public int getMinY() { + return minHeight; + } + + @Override + public int getMaxSectionPosition() { + return maxHeight >> 4; + } + + @Override + public int getMinSectionPosition() { + return minHeight >> 4; + } + + @Override + public BiomeType getBiomeType(int x, int y, int z) { + Holder biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2); + return PaperweightPlatformAdapter.adapt(biome, serverLevel); + } + + @Override + public void removeSectionLighting(int layer, boolean sky) { + } + + @Override + public boolean trim(boolean aggressive, int layer) { + return false; + } + + @Override + public IBlocks reset() { + return null; + } + + @Override + public int getSectionCount() { + return serverLevel.getSectionsCount(); + } + + protected void storeSection(int layer, char[] data) { + blocks[layer] = data; + } + + protected void storeBiomes(int layer, PalettedContainerRO> biomeData) { + if (biomes == null) { + biomes = new PalettedContainer[getSectionCount()]; + } + if (biomeData instanceof PalettedContainer> palettedContainer) { + biomes[layer] = palettedContainer.copy(); + } else { + LOGGER.error( + "Cannot correctly save biomes to history. Expected class type {} but got {}", + PalettedContainer.class.getSimpleName(), + biomeData.getClass().getSimpleName() + ); + } + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + BlockState state = BlockTypesCache.states[get(x, y, z)]; + return state.toBaseBlock(this, x, y, z); + } + + @Override + public boolean hasSection(int layer) { + layer -= getMinSectionPosition(); + return blocks[layer] != null; + } + + @Override + public char[] load(int layer) { + layer -= getMinSectionPosition(); + if (blocks[layer] == null) { + blocks[layer] = new char[4096]; + Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR); + } + return blocks[layer]; + } + + @Override + public char[] loadIfPresent(int layer) { + layer -= getMinSectionPosition(); + return blocks[layer]; + } + + @Override + public BlockState getBlock(int x, int y, int z) { + return BlockTypesCache.states[get(x, y, z)]; + } + + @Override + public int getSkyLight(int x, int y, int z) { + return 0; + } + + @Override + public int getEmittedLight(int x, int y, int z) { + return 0; + } + + @Override + public int[] getHeightMap(HeightMapType type) { + return new int[0]; + } + + @Override + public > T call(IChunkSet set, Runnable finalize) { + return null; + } + + public char get(int x, int y, int z) { + final int layer = (y >> 4) - getMinSectionPosition(); + final int index = (y & 15) << 8 | z << 4 | x; + return blocks[layer][index]; + } + + + @Override + public boolean trim(boolean aggressive) { + return false; + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightMapChunkUtil.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightMapChunkUtil.java new file mode 100644 index 000000000..97eecfc56 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightMapChunkUtil.java @@ -0,0 +1,34 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; + +import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; + +//TODO un-very-break-this +public class PaperweightMapChunkUtil extends MapChunkUtil { + + public PaperweightMapChunkUtil() throws NoSuchFieldException { + fieldX = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("TWO_MEGABYTES", "a")); + fieldZ = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("x", "a")); + fieldBitMask = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("z", "b")); + fieldHeightMap = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("heightmaps", "b")); + fieldChunkData = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("chunkData", "c")); + fieldBlockEntities = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("buffer", "c")); + fieldFull = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("blockEntitiesData", "d")); + fieldX.setAccessible(true); + fieldZ.setAccessible(true); + fieldBitMask.setAccessible(true); + fieldHeightMap.setAccessible(true); + fieldChunkData.setAccessible(true); + fieldBlockEntities.setAccessible(true); + fieldFull.setAccessible(true); + } + + @Override + public ClientboundLevelChunkWithLightPacket createPacket() { + // TODO ??? return new ClientboundLevelChunkPacket(); + throw new UnsupportedOperationException(); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java new file mode 100644 index 000000000..147ec5be7 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java @@ -0,0 +1,719 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; + +import com.destroystokyo.paper.util.maplist.EntityList; +import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; +import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; +import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.util.MathMan; +import com.fastasyncworldedit.core.util.ReflectionUtils; +import com.fastasyncworldedit.core.util.TaskManager; +import com.mojang.datafixers.util.Either; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +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.BlockTypesCache; +import io.papermc.lib.PaperLib; +import io.papermc.paper.world.ChunkEntitySlices; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.IdMap; +import net.minecraft.core.Registry; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.TicketType; +import net.minecraft.util.BitStorage; +import net.minecraft.util.ExceptionCollector; +import net.minecraft.util.SimpleBitStorage; +import net.minecraft.util.ThreadingDetector; +import net.minecraft.util.Unit; +import net.minecraft.util.ZeroBitStorage; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.GlobalPalette; +import net.minecraft.world.level.chunk.HashMapPalette; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.LinearPalette; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.SingleValuePalette; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import org.apache.logging.log4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_20_R3.CraftChunk; +import sun.misc.Unsafe; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Function; + +import static java.lang.invoke.MethodType.methodType; +import static net.minecraft.core.registries.Registries.BIOME; + +public final class PaperweightPlatformAdapter extends NMSAdapter { + + public static final Field fieldData; + + public static final Constructor dataConstructor; + + public static final Field fieldStorage; + public static final Field fieldPalette; + + private static final Field fieldTickingFluidCount; + private static final Field fieldTickingBlockCount; + private static final Field fieldNonEmptyBlockCount; + + private static final MethodHandle methodGetVisibleChunk; + + private static final Field fieldThreadingDetector; + private static final Field fieldLock; + + private static final MethodHandle methodRemoveGameEventListener; + private static final MethodHandle methodremoveTickingBlockEntity; + + /* + * This is a workaround for the changes from https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/1fddefce1cdce44010927b888432bf70c0e88cde#src/main/java/org/bukkit/craftbukkit/CraftChunk.java + * and is only needed to support 1.19.4 versions before *and* after this change. + */ + private static final MethodHandle CRAFT_CHUNK_GET_HANDLE; + + private static final Field fieldRemove; + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + static final boolean POST_CHUNK_REWRITE; + private static Method PAPER_CHUNK_GEN_ALL_ENTITIES; + private static Field LEVEL_CHUNK_ENTITIES; + private static Field SERVER_LEVEL_ENTITY_MANAGER; + + static { + final MethodHandles.Lookup lookup = MethodHandles.lookup(); + try { + fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d")); + fieldData.setAccessible(true); + + Class dataClazz = fieldData.getType(); + dataConstructor = dataClazz.getDeclaredConstructors()[0]; + dataConstructor.setAccessible(true); + + fieldStorage = dataClazz.getDeclaredField(Refraction.pickName("storage", "b")); + fieldStorage.setAccessible(true); + fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c")); + fieldPalette.setAccessible(true); + + fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "g")); + fieldTickingFluidCount.setAccessible(true); + fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); + fieldTickingBlockCount.setAccessible(true); + fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e")); + fieldNonEmptyBlockCount.setAccessible(true); + + Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( + "getVisibleChunkIfPresent", + "b" + ), long.class); + getVisibleChunkIfPresent.setAccessible(true); + methodGetVisibleChunk = lookup.unreflect(getVisibleChunkIfPresent); + + if (!PaperLib.isPaper()) { + fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); + fieldThreadingDetector.setAccessible(true); + fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); + fieldLock.setAccessible(true); + } else { + // in paper, the used methods are synchronized properly + fieldThreadingDetector = null; + fieldLock = null; + } + + Method removeGameEventListener = LevelChunk.class.getDeclaredMethod( + Refraction.pickName("removeGameEventListener", "a"), + BlockEntity.class, + ServerLevel.class + ); + removeGameEventListener.setAccessible(true); + methodRemoveGameEventListener = lookup.unreflect(removeGameEventListener); + + Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod( + Refraction.pickName( + "removeBlockEntityTicker", + "l" + ), BlockPos.class + ); + removeBlockEntityTicker.setAccessible(true); + methodremoveTickingBlockEntity = lookup.unreflect(removeBlockEntityTicker); + + fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "q")); + fieldRemove.setAccessible(true); + + boolean chunkRewrite; + try { + ServerLevel.class.getDeclaredMethod("getEntityLookup"); + chunkRewrite = true; + PAPER_CHUNK_GEN_ALL_ENTITIES = ChunkEntitySlices.class.getDeclaredMethod("getAllEntities"); + PAPER_CHUNK_GEN_ALL_ENTITIES.setAccessible(true); + } catch (NoSuchMethodException ignored) { + chunkRewrite = false; + } + try { + // Paper - Pre-Chunk-Update + LEVEL_CHUNK_ENTITIES = LevelChunk.class.getDeclaredField("entities"); + LEVEL_CHUNK_ENTITIES.setAccessible(true); + } catch (NoSuchFieldException ignored) { + } + try { + // Non-Paper + SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "M")); + SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true); + } catch (NoSuchFieldException ignored) { + } + POST_CHUNK_REWRITE = chunkRewrite; + } catch (RuntimeException | Error e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + MethodHandle craftChunkGetHandle; + final MethodType type = methodType(LevelChunk.class); + try { + craftChunkGetHandle = lookup.findVirtual(CraftChunk.class, "getHandle", type); + } catch (NoSuchMethodException | IllegalAccessException e) { + try { + final MethodType newType = methodType(ChunkAccess.class, ChunkStatus.class); + craftChunkGetHandle = lookup.findVirtual(CraftChunk.class, "getHandle", newType); + craftChunkGetHandle = MethodHandles.insertArguments(craftChunkGetHandle, 1, ChunkStatus.FULL); + } catch (NoSuchMethodException | IllegalAccessException ex) { + throw new RuntimeException(ex); + } + } + CRAFT_CHUNK_GET_HANDLE = craftChunkGetHandle; + } + + static boolean setSectionAtomic( + LevelChunkSection[] sections, + LevelChunkSection expected, + LevelChunkSection value, + int layer + ) { + if (layer >= 0 && layer < sections.length) { + return ReflectionUtils.compareAndSet(sections, expected, value, layer); + } + return false; + } + + // There is no point in having a functional semaphore for paper servers. + private static final ThreadLocal SEMAPHORE_THREAD_LOCAL = + ThreadLocal.withInitial(() -> new DelegateSemaphore(1, null)); + + static DelegateSemaphore applyLock(LevelChunkSection section) { + if (PaperLib.isPaper()) { + return SEMAPHORE_THREAD_LOCAL.get(); + } + try { + synchronized (section) { + PalettedContainer blocks = section.getStates(); + ThreadingDetector currentThreadingDetector = (ThreadingDetector) fieldThreadingDetector.get(blocks); + synchronized (currentThreadingDetector) { + Semaphore currentLock = (Semaphore) fieldLock.get(currentThreadingDetector); + if (currentLock instanceof DelegateSemaphore delegateSemaphore) { + return delegateSemaphore; + } + DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); + fieldLock.set(currentThreadingDetector, newLock); + return newLock; + } + } + } catch (Throwable e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) { + if (!PaperLib.isPaper()) { + LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false); + if (nmsChunk != null) { + return nmsChunk; + } + if (Fawe.isMainThread()) { + return serverLevel.getChunk(chunkX, chunkZ); + } + } else { + LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ); + if (nmsChunk != null) { + addTicket(serverLevel, chunkX, chunkZ); + return nmsChunk; + } + nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ); + if (nmsChunk != null) { + addTicket(serverLevel, chunkX, chunkZ); + return nmsChunk; + } + // Avoid "async" methods from the main thread. + if (Fawe.isMainThread()) { + return serverLevel.getChunk(chunkX, chunkZ); + } + CompletableFuture future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true); + try { + CraftChunk chunk; + try { + chunk = (CraftChunk) future.get(10, TimeUnit.SECONDS); + } catch (TimeoutException e) { + String world = serverLevel.getWorld().getName(); + // We've already taken 10 seconds we can afford to wait a little here. + boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null); + if (loaded) { + LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world); + // Retry chunk load + chunk = (CraftChunk) serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true).get(); + } else { + throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!"); + } + } + addTicket(serverLevel, chunkX, chunkZ); + return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk); + } catch (Throwable e) { + e.printStackTrace(); + } + } + return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)); + } + + private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) { + // Ensure chunk is definitely loaded before applying a ticket + io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel + .getChunkSource() + .addRegionTicket(TicketType.UNLOAD_COOLDOWN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE)); + } + + public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) { + ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap; + try { + return (ChunkHolder) methodGetVisibleChunk.invoke(chunkMap, ChunkPos.asLong(chunkX, chunkZ)); + } catch (Throwable thr) { + throw new RuntimeException(thr); + } + } + + @SuppressWarnings("deprecation") + public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) { + ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); + if (chunkHolder == null) { + return; + } + ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ); + LevelChunk levelChunk; + if (PaperLib.isPaper()) { + // getChunkAtIfLoadedImmediately is paper only + levelChunk = nmsWorld + .getChunkSource() + .getChunkAtIfLoadedImmediately(chunkX, chunkZ); + } else { + levelChunk = ((Optional) ((Either) chunkHolder + .getTickingChunkFuture() // method is not present with new paper chunk system + .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left()) + .orElse(null); + } + if (levelChunk == null) { + return; + } + TaskManager.taskManager().task(() -> { + ClientboundLevelChunkWithLightPacket packet; + if (PaperLib.isPaper()) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + // last false is to not bother with x-ray + ); + } else { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); + } + nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); + }); + } + + private static List nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) { + return serverLevel.getChunkSource().chunkMap.getPlayers(coordIntPair, false); + } + + /* + NMS conversion + */ + public static LevelChunkSection newChunkSection( + final int layer, + final char[] blocks, + CachedBukkitAdapter adapter, + Registry biomeRegistry, + @Nullable PalettedContainer> biomes + ) { + return newChunkSection(layer, null, blocks, adapter, biomeRegistry, biomes); + } + + public static LevelChunkSection newChunkSection( + final int layer, + final Function get, + char[] set, + CachedBukkitAdapter adapter, + Registry biomeRegistry, + @Nullable PalettedContainer> biomes + ) { + if (set == null) { + return newChunkSection(layer, biomeRegistry, biomes); + } + final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); + final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); + final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get(); + final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get(); + try { + int num_palette; + if (get == null) { + num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter, null); + } else { + num_palette = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, get, set, adapter, null); + } + + int bitsPerEntry = MathMan.log2nlz(num_palette - 1); + if (bitsPerEntry > 0 && bitsPerEntry < 5) { + bitsPerEntry = 4; + } else if (bitsPerEntry > 8) { + bitsPerEntry = MathMan.log2nlz(Block.BLOCK_STATE_REGISTRY.size() - 1); + } + + int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes + final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); + final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong); + + if (num_palette == 1) { + for (int i = 0; i < blockBitArrayEnd; i++) { + blockStates[i] = 0; + } + } else { + final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntryNonZero, 4096, blockStates); + bitArray.fromRaw(blocksCopy); + } + + final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd); + final BitStorage nmsBits; + if (bitsPerEntry == 0) { + nmsBits = new ZeroBitStorage(4096); + } else { + nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits); + } + List palette; + if (bitsPerEntry < 9) { + palette = new ArrayList<>(); + for (int i = 0; i < num_palette; i++) { + int ordinal = paletteToBlock[i]; + blockToPalette[ordinal] = Integer.MAX_VALUE; + final BlockState state = BlockTypesCache.states[ordinal]; + palette.add(((PaperweightBlockMaterial) state.getMaterial()).getState()); + } + } else { + palette = List.of(); + } + + // Create palette with data + @SuppressWarnings("deprecation") // constructor is deprecated on paper, but needed to keep compatibility with spigot + final PalettedContainer blockStatePalettedContainer = + new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, + PalettedContainer.Strategy.SECTION_STATES, + PalettedContainer.Strategy.SECTION_STATES.getConfiguration(Block.BLOCK_STATE_REGISTRY, bitsPerEntry), + nmsBits, + palette + ); + if (biomes == null) { + IdMap> biomeHolderIdMap = biomeRegistry.asHolderIdMap(); + biomes = new PalettedContainer<>( + biomeHolderIdMap, + biomeHolderIdMap.byIdOrThrow(WorldEditPlugin + .getInstance() + .getBukkitImplAdapter() + .getInternalBiomeId( + BiomeTypes.PLAINS)), + PalettedContainer.Strategy.SECTION_BIOMES + ); + } + + return new LevelChunkSection(blockStatePalettedContainer, biomes); + } catch (final Throwable e) { + throw e; + } finally { + Arrays.fill(blockToPalette, Integer.MAX_VALUE); + Arrays.fill(paletteToBlock, Integer.MAX_VALUE); + Arrays.fill(blockStates, 0); + Arrays.fill(blocksCopy, 0); + } + } + + @SuppressWarnings("deprecation") // Only deprecated in paper + private static LevelChunkSection newChunkSection( + int layer, + Registry biomeRegistry, + @Nullable PalettedContainer> biomes + ) { + if (biomes == null) { + return new LevelChunkSection(biomeRegistry); + } + PalettedContainer dataPaletteBlocks = new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), + PalettedContainer.Strategy.SECTION_STATES + ); + return new LevelChunkSection(dataPaletteBlocks, biomes); + } + + /** + * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. + */ + public static PalettedContainer> getBiomePalettedContainer( + BiomeType[] biomes, + IdMap> biomeRegistry + ) { + if (biomes == null) { + return null; + } + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + // Don't stream this as typically will see 1-4 biomes; stream overhead is large for the small length + Map> palette = new HashMap<>(); + for (BiomeType biomeType : new LinkedList<>(Arrays.asList(biomes))) { + Holder biome; + if (biomeType == null) { + biome = biomeRegistry.byId(adapter.getInternalBiomeId(BiomeTypes.PLAINS)); + } else { + biome = biomeRegistry.byId(adapter.getInternalBiomeId(biomeType)); + } + palette.put(biomeType, biome); + } + int biomeCount = palette.size(); + int bitsPerEntry = MathMan.log2nlz(biomeCount - 1); + Object configuration = PalettedContainer.Strategy.SECTION_STATES.getConfiguration( + new FakeIdMapBiome(biomeCount), + bitsPerEntry + ); + if (bitsPerEntry > 3) { + bitsPerEntry = MathMan.log2nlz(biomeRegistry.size() - 1); + } + PalettedContainer> biomePalettedContainer = new PalettedContainer<>( + biomeRegistry, + biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), + PalettedContainer.Strategy.SECTION_BIOMES + ); + + final Palette> biomePalette; + if (bitsPerEntry == 0) { + biomePalette = new SingleValuePalette<>( + biomePalettedContainer.registry, + biomePalettedContainer, + new ArrayList<>(palette.values()) // Must be modifiable + ); + } else if (bitsPerEntry == 4) { + biomePalette = LinearPalette.create( + 4, + biomePalettedContainer.registry, + biomePalettedContainer, + new ArrayList<>(palette.values()) // Must be modifiable + ); + } else if (bitsPerEntry < 9) { + biomePalette = HashMapPalette.create( + bitsPerEntry, + biomePalettedContainer.registry, + biomePalettedContainer, + new ArrayList<>(palette.values()) // Must be modifiable + ); + } else { + biomePalette = GlobalPalette.create( + bitsPerEntry, + biomePalettedContainer.registry, + biomePalettedContainer, + null // unused + ); + } + + int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes + final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); + final int arrayLength = MathMan.ceilZero(64f / blocksPerLong); + + + BitStorage bitStorage = bitsPerEntry == 0 ? new ZeroBitStorage(64) : new SimpleBitStorage( + bitsPerEntry, + 64, + new long[arrayLength] + ); + + try { + Object data = dataConstructor.newInstance(configuration, bitStorage, biomePalette); + fieldData.set(biomePalettedContainer, data); + int index = 0; + for (int y = 0; y < 4; y++) { + for (int z = 0; z < 4; z++) { + for (int x = 0; x < 4; x++, index++) { + BiomeType biomeType = biomes[index]; + if (biomeType == null) { + continue; + } + Holder biome = biomeRegistry.byId(WorldEditPlugin + .getInstance() + .getBukkitImplAdapter() + .getInternalBiomeId(biomeType)); + if (biome == null) { + continue; + } + biomePalettedContainer.set(x, y, z, biome); + } + } + } + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + return biomePalettedContainer; + } + + public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException { + fieldTickingFluidCount.setShort(section, (short) 0); + fieldTickingBlockCount.setShort(section, (short) 0); + } + + public static BiomeType adapt(Holder biome, LevelAccessor levelAccessor) { + final Registry biomeRegistry = levelAccessor.registryAccess().registryOrThrow(BIOME); + if (biomeRegistry.getKey(biome.value()) == null) { + return biomeRegistry.asHolderIdMap().getId(biome) == -1 ? BiomeTypes.OCEAN + : null; + } + return BiomeTypes.get(biome.unwrapKey().orElseThrow().location().toString()); + } + + static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { + try { + if (levelChunk.loaded || levelChunk.level.isClientSide()) { + BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos()); + if (blockEntity != null) { + if (!levelChunk.level.isClientSide) { + methodRemoveGameEventListener.invoke(levelChunk, beacon, levelChunk.level); + } + fieldRemove.set(beacon, true); + } + } + methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos()); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + + static List getEntities(LevelChunk chunk) { + ExceptionCollector collector = new ExceptionCollector<>(); + if (PaperLib.isPaper()) { + if (POST_CHUNK_REWRITE) { + try { + //noinspection unchecked + return (List) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level.getEntityLookup().getChunk(chunk.locX, chunk.locZ)); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=true]", e); + } + } + try { + EntityList entityList = (EntityList) LEVEL_CHUNK_ENTITIES.get(chunk); + return List.of(entityList.getRawData()); + } catch (IllegalAccessException e) { + collector.add(new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=false]", e)); + // fall through + } + } + try { + //noinspection unchecked + return ((PersistentEntitySectionManager) (SERVER_LEVEL_ENTITY_MANAGER.get(chunk.level))).getEntities(chunk.getPos()); + } catch (IllegalAccessException e) { + collector.add(new RuntimeException("Failed to lookup entities [PAPER=false]", e)); + } + collector.throwIfPresent(); + return List.of(); + } + + record FakeIdMapBlock(int size) implements IdMap { + + @Override + public int getId(final net.minecraft.world.level.block.state.BlockState entry) { + return 0; + } + + @Nullable + @Override + public net.minecraft.world.level.block.state.BlockState byId(final int index) { + return null; + } + + @Nonnull + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + + } + + record FakeIdMapBiome(int size) implements IdMap { + + @Override + public int getId(final Biome entry) { + return 0; + } + + @Nullable + @Override + public Biome byId(final int index) { + return null; + } + + @Nonnull + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPostProcessor.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPostProcessor.java new file mode 100644 index 000000000..cfd9e2753 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPostProcessor.java @@ -0,0 +1,175 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; + +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.extent.processor.ProcessorScope; +import com.fastasyncworldedit.core.queue.IBatchProcessor; +import com.fastasyncworldedit.core.queue.IChunk; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import com.fastasyncworldedit.core.registry.state.PropertyKey; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.Fluids; + +import javax.annotation.Nullable; + +public class PaperweightPostProcessor implements IBatchProcessor { + + @Override + public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) { + return set; + } + + @SuppressWarnings("deprecation") + @Override + public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) { + boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS; + // The PostProcessor shouldn't be added, but just in case + if (!tickFluid) { + return; + } + PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet; + layer: + for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) { + char[] set = iChunkSet.loadIfPresent(layer); + if (set == null) { + // No edit means no need to process + continue; + } + char[] get = null; + for (int i = 0; i < 4096; i++) { + char ordinal = set[i]; + char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__; + boolean fromGet = false; // Used for liquids + if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { + if (get == null) { + get = getBlocks.load(layer); + } + // If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't + // actually being set + if (get == null) { + continue layer; + } + fromGet = true; + ordinal = replacedOrdinal = get[i]; + } + if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { + continue; + } else if (!fromGet) { // if fromGet, don't do the same again + if (get == null) { + get = getBlocks.load(layer); + } + replacedOrdinal = get[i]; + } + boolean ticking = BlockTypesCache.ticking[ordinal]; + boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal]; + boolean replacedWasLiquid = false; + BlockState replacedState = null; + if (!ticking) { + // If the block being replaced was not ticking, it cannot be a liquid + if (!replacedWasTicking) { + continue; + } + // If the block being replaced is not fluid, we do not need to worry + if (!(replacedWasLiquid = + (replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) { + continue; + } + } + BlockState state = BlockState.getFromOrdinal(ordinal); + boolean liquid = state.getMaterial().isLiquid(); + int x = i & 15; + int y = (i >> 8) & 15; + int z = (i >> 4) & 15; + BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z); + if (liquid || replacedWasLiquid) { + if (liquid) { + addFluid(getBlocks.serverLevel, state, position); + continue; + } + // If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this + // may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up + // being ticked anyway. We only need it to be "hit" once. + if (!wasAdjacentToWater(get, set, i, x, y, z)) { + continue; + } + addFluid(getBlocks.serverLevel, replacedState, position); + } + } + } + } + + @Nullable + @Override + public Extent construct(final Extent child) { + throw new UnsupportedOperationException("Processing only"); + } + + @Override + public ProcessorScope getScope() { + return ProcessorScope.READING_SET_BLOCKS; + } + + private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) { + if (set == null || get == null) { + return false; + } + char ordinal; + char reserved = BlockTypesCache.ReservedIDs.__RESERVED__; + if (x > 0 && set[i - 1] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) { + return true; + } + } + if (x < 15 && set[i + 1] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) { + return true; + } + } + if (z > 0 && set[i - 16] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) { + return true; + } + } + if (z < 15 && set[i + 16] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) { + return true; + } + } + if (y > 0 && set[i - 256] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) { + return true; + } + } + if (y < 15 && set[i + 256] != reserved) { + return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal); + } + return false; + } + + @SuppressWarnings("deprecation") + private boolean isFluid(char ordinal) { + return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid(); + } + + @SuppressWarnings("deprecation") + private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) { + Fluid type; + if (replacedState.getBlockType() == BlockTypes.LAVA) { + type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA; + } else { + type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER; + } + serverLevel.scheduleTick( + position, + type, + type.getTickDelay(serverLevel) + ); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java new file mode 100644 index 000000000..49f02bf8d --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java @@ -0,0 +1,76 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; + +import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.queue.IQueueExtent; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.TicketType; +import net.minecraft.util.Unit; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.ChunkStatus; + +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.IntConsumer; + +public class PaperweightStarlightRelighter extends StarlightRelighter { + + private static final TicketType FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); + private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkStatus.getDistance(ChunkStatus.LIGHT); + + public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { + super(serverLevel, queue); + } + + @Override + protected ChunkPos createChunkPos(final long chunkKey) { + return new ChunkPos(chunkKey); + } + + @Override + protected long asLong(final int chunkX, final int chunkZ) { + return ChunkPos.asLong(chunkX, chunkZ); + } + + @Override + protected CompletableFuture chunkLoadFuture(final ChunkPos chunkPos) { + return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z) + .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( + FAWE_TICKET, + chunkPos, + LIGHT_LEVEL, + Unit.INSTANCE + )); + } + + protected void invokeRelight( + Set coords, + Consumer chunkCallback, + IntConsumer processCallback + ) { + try { + serverLevel.getChunkSource().getLightEngine().relight(coords, chunkCallback, processCallback); + } catch (Exception e) { + LOGGER.error("Error occurred on relighting", e); + } + } + + /* + * Allow the server to unload the chunks again. + * Also, if chunk packets are sent delayed, we need to do that here + */ + protected void postProcessChunks(Set coords) { + boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING; + for (ChunkPos pos : coords) { + int x = pos.x; + int z = pos.z; + if (delay) { // we still need to send the block changes of that chunk + PaperweightPlatformAdapter.sendChunk(serverLevel, x, z, false); + } + serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE); + } + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighterFactory.java new file mode 100644 index 000000000..bf9a4e8df --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighterFactory.java @@ -0,0 +1,25 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; + +import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; +import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; +import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; +import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; +import com.fastasyncworldedit.core.queue.IQueueExtent; +import com.sk89q.worldedit.world.World; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; + +import javax.annotation.Nonnull; + +public class PaperweightStarlightRelighterFactory implements RelighterFactory { + + @Override + public @Nonnull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { + org.bukkit.World w = Bukkit.getWorld(world.getName()); + if (w == null) { + return NullRelighter.INSTANCE; + } + return new PaperweightStarlightRelighter(((CraftWorld) w).getHandle(), queue); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/nbt/PaperweightLazyCompoundTag.java new file mode 100644 index 000000000..9a8a51896 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/nbt/PaperweightLazyCompoundTag.java @@ -0,0 +1,161 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.LazyCompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import net.minecraft.nbt.NumericTag; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +public class PaperweightLazyCompoundTag extends LazyCompoundTag { + + private final Supplier compoundTagSupplier; + private CompoundTag compoundTag; + + public PaperweightLazyCompoundTag(Supplier compoundTagSupplier) { + super(new HashMap<>()); + this.compoundTagSupplier = compoundTagSupplier; + } + + public PaperweightLazyCompoundTag(net.minecraft.nbt.CompoundTag compoundTag) { + this(() -> compoundTag); + } + + public net.minecraft.nbt.CompoundTag get() { + return compoundTagSupplier.get(); + } + + @Override + @SuppressWarnings("unchecked") + public Map getValue() { + if (compoundTag == null) { + compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); + } + return compoundTag.getValue(); + } + + @Override + public CompoundBinaryTag asBinaryTag() { + getValue(); + return compoundTag.asBinaryTag(); + } + + public boolean containsKey(String key) { + return compoundTagSupplier.get().contains(key); + } + + public byte[] getByteArray(String key) { + return compoundTagSupplier.get().getByteArray(key); + } + + public byte getByte(String key) { + return compoundTagSupplier.get().getByte(key); + } + + public double getDouble(String key) { + return compoundTagSupplier.get().getDouble(key); + } + + public double asDouble(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof NumericTag numTag) { + return numTag.getAsDouble(); + } + return 0; + } + + public float getFloat(String key) { + return compoundTagSupplier.get().getFloat(key); + } + + public int[] getIntArray(String key) { + return compoundTagSupplier.get().getIntArray(key); + } + + public int getInt(String key) { + return compoundTagSupplier.get().getInt(key); + } + + public int asInt(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof NumericTag numTag) { + return numTag.getAsInt(); + } + return 0; + } + + @SuppressWarnings("unchecked") + public List getList(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof net.minecraft.nbt.ListTag nbtList) { + ArrayList list = new ArrayList<>(); + for (net.minecraft.nbt.Tag elem : nbtList) { + if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { + list.add(new PaperweightLazyCompoundTag(compoundTag)); + } else { + list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem)); + } + } + return list; + } + return Collections.emptyList(); + } + + @SuppressWarnings("unchecked") + public ListTag getListTag(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof net.minecraft.nbt.ListTag) { + return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag); + } + return new ListTag(StringTag.class, Collections.emptyList()); + } + + @SuppressWarnings("unchecked") + public List getList(String key, Class listType) { + ListTag listTag = getListTag(key); + if (listTag.getType().equals(listType)) { + return (List) listTag.getValue(); + } else { + return Collections.emptyList(); + } + } + + public long[] getLongArray(String key) { + return compoundTagSupplier.get().getLongArray(key); + } + + public long getLong(String key) { + return compoundTagSupplier.get().getLong(key); + } + + public long asLong(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof NumericTag numTag) { + return numTag.getAsLong(); + } + return 0; + } + + public short getShort(String key) { + return compoundTagSupplier.get().getShort(key); + } + + public String getString(String key) { + return compoundTagSupplier.get().getString(key); + } + + @Override + public String toString() { + return compoundTagSupplier.get().toString(); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/regen/PaperweightRegen.java new file mode 100644 index 000000000..edf9e9f90 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/regen/PaperweightRegen.java @@ -0,0 +1,590 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.regen; + +import com.fastasyncworldedit.bukkit.adapter.Regenerator; +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.queue.IChunkCache; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.util.TaskManager; +import com.google.common.collect.ImmutableList; +import com.mojang.datafixers.util.Either; +import com.mojang.serialization.Lifecycle; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.PaperweightGetBlocks; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.io.file.SafeFiles; +import com.sk89q.worldedit.world.RegenOptions; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.util.thread.ProcessorHandle; +import net.minecraft.util.thread.ProcessorMailbox; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.LevelSettings; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.biome.FixedBiomeSource; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.levelgen.WorldOptions; +import net.minecraft.world.level.levelgen.blending.BlendingData; +import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; +import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; +import net.minecraft.world.level.storage.LevelStorageSource; +import net.minecraft.world.level.storage.PrimaryLevelData; +import org.apache.logging.log4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.craftbukkit.v1_20_R3.CraftServer; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator; +import org.bukkit.generator.BiomeProvider; +import org.bukkit.generator.BlockPopulator; + +import javax.annotation.Nullable; +import java.lang.reflect.Field; +import java.nio.file.Path; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.OptionalLong; +import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.function.BooleanSupplier; +import java.util.function.Supplier; + +import static net.minecraft.core.registries.Registries.BIOME; + +public class PaperweightRegen extends Regenerator { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private static final Field serverWorldsField; + private static final Field paperConfigField; + private static final Field flatBedrockField; + private static final Field generatorSettingFlatField; + private static final Field generatorSettingBaseSupplierField; + private static final Field delegateField; + private static final Field chunkSourceField; + private static final Field generatorStructureStateField; + private static final Field ringPositionsField; + private static final Field hasGeneratedPositionsField; + + //list of chunk stati in correct order without FULL + private static final Map chunkStati = new LinkedHashMap<>(); + + static { + chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing + chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps + chunkStati.put( + ChunkStatus.STRUCTURE_REFERENCES, + Concurrency.FULL + ); // structure refs: radius 8, but only writes to current chunk + chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // biomes: radius 0 + chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8 + chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE + chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results + /*chunkStati.put( + ChunkStatus.LIQUID_CARVERS, + Concurrency.NONE + ); // liquid carvers: radius 0, but RADIUS and FULL change results*/ + chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps + chunkStati.put( + ChunkStatus.LIGHT, + Concurrency.FULL + ); // light: radius 1, but no writes to other chunks, only current chunk + chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0 + // chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0 + + try { + serverWorldsField = CraftServer.class.getDeclaredField("worlds"); + serverWorldsField.setAccessible(true); + + Field tmpPaperConfigField; + Field tmpFlatBedrockField; + try { //only present on paper + tmpPaperConfigField = Level.class.getDeclaredField("paperConfig"); + tmpPaperConfigField.setAccessible(true); + + tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock"); + tmpFlatBedrockField.setAccessible(true); + } catch (Exception e) { + tmpPaperConfigField = null; + tmpFlatBedrockField = null; + } + paperConfigField = tmpPaperConfigField; + flatBedrockField = tmpFlatBedrockField; + + generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName( + "settings", "e")); + generatorSettingBaseSupplierField.setAccessible(true); + + generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "d")); + generatorSettingFlatField.setAccessible(true); + + delegateField = CustomChunkGenerator.class.getDeclaredField("delegate"); + delegateField.setAccessible(true); + + chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "I")); + chunkSourceField.setAccessible(true); + + generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "v")); + generatorStructureStateField.setAccessible(true); + + ringPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(Refraction.pickName("ringPositions", "g")); + ringPositionsField.setAccessible(true); + + hasGeneratedPositionsField = ChunkGeneratorStructureState.class.getDeclaredField( + Refraction.pickName("hasGeneratedPositions", "h") + ); + hasGeneratedPositionsField.setAccessible(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + //runtime + private ServerLevel originalServerWorld; + private ServerChunkCache originalChunkProvider; + private ServerLevel freshWorld; + private ServerChunkCache freshChunkProvider; + private LevelStorageSource.LevelStorageAccess session; + private StructureTemplateManager structureTemplateManager; + private ThreadedLevelLightEngine threadedLevelLightEngine; + private ChunkGenerator chunkGenerator; + + private Path tempDir; + + private boolean generateFlatBedrock = false; + + public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) { + super(originalBukkitWorld, region, target, options); + } + + @Override + protected boolean prepare() { + this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle(); + originalChunkProvider = originalServerWorld.getChunkSource(); + + //flat bedrock? (only on paper) + if (paperConfigField != null) { + try { + generateFlatBedrock = flatBedrockField.getBoolean(paperConfigField.get(originalServerWorld)); + } catch (Exception ignored) { + } + } + + seed = options.getSeed().orElse(originalServerWorld.getSeed()); + chunkStati.forEach((s, c) -> super.chunkStatuses.put(new ChunkStatusWrap(s), c)); + + return true; + } + + @Override + @SuppressWarnings("unchecked") + protected boolean initNewWorld() throws Exception { + //world folder + tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen"); + + //prepare for world init (see upstream implementation for reference) + org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment(); + org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator(); + LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir); + ResourceKey levelStemResourceKey = getWorldDimKey(environment); + session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey); + PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData; + + MinecraftServer server = originalServerWorld.getCraftServer().getServer(); + WorldOptions originalOpts = originalWorldData.worldGenOptions(); + WorldOptions newOpts = options.getSeed().isPresent() + ? originalOpts.withSeed(OptionalLong.of(seed)) + : originalOpts; + LevelSettings newWorldSettings = new LevelSettings( + "faweregentempworld", + originalWorldData.settings.gameType(), + originalWorldData.settings.hardcore(), + originalWorldData.settings.difficulty(), + originalWorldData.settings.allowCommands(), + originalWorldData.settings.gameRules(), + originalWorldData.settings.getDataConfiguration() + ); + + PrimaryLevelData.SpecialWorldProperty specialWorldProperty = + originalWorldData.isFlatWorld() + ? PrimaryLevelData.SpecialWorldProperty.FLAT + : originalWorldData.isDebugWorld() + ? PrimaryLevelData.SpecialWorldProperty.DEBUG + : PrimaryLevelData.SpecialWorldProperty.NONE; + PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable()); + + BiomeProvider biomeProvider = getBiomeProvider(); + + + //init world + freshWorld = Fawe.instance().getQueueHandler().sync((Supplier) () -> new ServerLevel( + server, + server.executor, + session, + newWorldData, + originalServerWorld.dimension(), + DedicatedServer.getServer().registryAccess().registry(Registries.LEVEL_STEM).orElseThrow() + .getOrThrow(levelStemResourceKey), + new RegenNoOpWorldLoadListener(), + originalServerWorld.isDebug(), + seed, + ImmutableList.of(), + false, + originalServerWorld.getRandomSequences(), + environment, + generator, + biomeProvider + ) { + + private final Holder singleBiome = options.hasBiomeType() ? DedicatedServer.getServer().registryAccess() + .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( + WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) + ) : null; + + @Override + public void tick(BooleanSupplier shouldKeepTicking) { //no ticking + } + + @Override + public Holder getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { + if (options.hasBiomeType()) { + return singleBiome; + } + return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome( + biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler() + ); + } + }).get(); + freshWorld.noSave = true; + removeWorldFromWorldsMap(); + newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name + if (paperConfigField != null) { + paperConfigField.set(freshWorld, originalServerWorld.paperConfig()); + } + + ChunkGenerator originalGenerator = originalChunkProvider.getGenerator(); + if (originalGenerator instanceof FlatLevelSource flatLevelSource) { + FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings(); + chunkGenerator = new FlatLevelSource(generatorSettingFlat); + } else if (originalGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + Holder generatorSettingBaseSupplier = (Holder) generatorSettingBaseSupplierField.get( + originalGenerator); + BiomeSource biomeSource; + if (options.hasBiomeType()) { + + biomeSource = new FixedBiomeSource( + DedicatedServer.getServer().registryAccess() + .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( + WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) + ) + ); + } else { + biomeSource = originalGenerator.getBiomeSource(); + } + chunkGenerator = new NoiseBasedChunkGenerator( + biomeSource, + generatorSettingBaseSupplier + ); + } else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) { + chunkGenerator = customChunkGenerator.getDelegate(); + } else { + LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName()); + return false; + } + if (generator != null) { + chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator); + generateConcurrent = generator.isParallelCapable(); + } +// chunkGenerator.conf = freshWorld.spigotConfig; - Does not exist anymore, may need to be re-addressed + + freshChunkProvider = new ServerChunkCache( + freshWorld, + session, + server.getFixerUpper(), + server.getStructureManager(), + server.executor, + chunkGenerator, + freshWorld.spigotConfig.viewDistance, + freshWorld.spigotConfig.simulationDistance, + server.forceSynchronousWrites(), + new RegenNoOpWorldLoadListener(), + (chunkCoordIntPair, state) -> { + }, + () -> server.overworld().getDataStorage() + ) { + // redirect to LevelChunks created in #createChunks + @Override + public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean create) { + ChunkAccess chunkAccess = getChunkAt(x, z); + if (chunkAccess == null && create) { + chunkAccess = createChunk(getProtoChunkAt(x, z)); + } + return chunkAccess; + } + }; + + if (seed == originalOpts.seed() && !options.hasBiomeType()) { + // Optimisation for needless ring position calculation when the seed and biome is the same. + ChunkGeneratorStructureState state = (ChunkGeneratorStructureState) generatorStructureStateField.get(originalChunkProvider.chunkMap); + boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(state); + if (hasGeneratedPositions) { + Map>> origPositions = + (Map>>) ringPositionsField.get(state); + Map>> copy = new Object2ObjectArrayMap<>( + origPositions); + ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get(freshChunkProvider.chunkMap); + ringPositionsField.set(newState, copy); + hasGeneratedPositionsField.setBoolean(newState, true); + } + } + + + chunkSourceField.set(freshWorld, freshChunkProvider); + //let's start then + structureTemplateManager = server.getStructureManager(); + threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider); + + return true; + } + + @Override + protected void cleanup() { + try { + session.close(); + } catch (Exception ignored) { + } + + //shutdown chunk provider + try { + Fawe.instance().getQueueHandler().sync(() -> { + try { + freshChunkProvider.close(false); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } catch (Exception ignored) { + } + + //remove world from server + try { + Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap); + } catch (Exception ignored) { + } + + //delete directory + try { + SafeFiles.tryHardToDeleteDir(tempDir); + } catch (Exception ignored) { + } + } + + @Override + protected ProtoChunk createProtoChunk(int x, int z) { + return new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld, + this.freshWorld.registryAccess().registryOrThrow(BIOME), null + ); + } + + @Override + protected LevelChunk createChunk(ProtoChunk protoChunk) { + return new LevelChunk( + freshWorld, + protoChunk, + null // we don't want to add entities + ); + } + + @Override + protected ChunkStatusWrap getFullChunkStatus() { + return new ChunkStatusWrap(ChunkStatus.FULL); + } + + @Override + protected List getBlockPopulators() { + return originalServerWorld.getWorld().getPopulators(); + } + + @Override + protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) { + // BlockPopulator#populate has to be called synchronously for TileEntity access + TaskManager.taskManager().task(() -> { + final CraftWorld world = freshWorld.getWorld(); + final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ); + blockPopulator.populate(world, random, chunk); + }); + } + + @Override + protected IChunkCache initSourceQueueCache() { + return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) { + @Override + public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) { + return getChunkAt(x, z); + } + }; + } + + //util + @SuppressWarnings("unchecked") + private void removeWorldFromWorldsMap() { + Fawe.instance().getQueueHandler().sync(() -> { + try { + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); + map.remove("faweregentempworld"); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + }); + } + + private ResourceKey getWorldDimKey(org.bukkit.World.Environment env) { + return switch (env) { + case NETHER -> LevelStem.NETHER; + case THE_END -> LevelStem.END; + default -> LevelStem.OVERWORLD; + }; + } + + private static class RegenNoOpWorldLoadListener implements ChunkProgressListener { + + private RegenNoOpWorldLoadListener() { + } + + @Override + public void updateSpawnPos(ChunkPos spawnPos) { + } + + @Override + public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) { + } + + @Override + public void start() { + + } + + @Override + public void stop() { + } + + // TODO Paper only(?) @Override + public void setChunkRadius(int radius) { + } + + } + + private class FastProtoChunk extends ProtoChunk { + + public FastProtoChunk( + final ChunkPos pos, + final UpgradeData upgradeData, + final LevelHeightAccessor world, + final Registry biomeRegistry, + @Nullable final BlendingData blendingData + ) { + super(pos, upgradeData, world, biomeRegistry, blendingData); + } + + // avoid warning on paper + + // compatibility with spigot + + public boolean generateFlatBedrock() { + return generateFlatBedrock; + } + + // no one will ever see the entities! + @Override + public List getEntities() { + return Collections.emptyList(); + } + + } + + protected class ChunkStatusWrap extends ChunkStatusWrapper { + + private final ChunkStatus chunkStatus; + + public ChunkStatusWrap(ChunkStatus chunkStatus) { + this.chunkStatus = chunkStatus; + } + + @Override + public int requiredNeighborChunkRadius() { + return chunkStatus.getRange(); + } + + @Override + public String name() { + return chunkStatus.toString(); + } + + @Override + public CompletableFuture processChunk(List accessibleChunks) { + return chunkStatus.generate( + Runnable::run, // TODO revisit, we might profit from this somehow? + freshWorld, + chunkGenerator, + structureTemplateManager, + threadedLevelLightEngine, + c -> CompletableFuture.completedFuture(Either.left(c)), + accessibleChunks + ); + } + + } + + /** + * A light engine that does nothing. As light is calculated after pasting anyway, we can avoid + * work this way. + */ + static class NoOpLightEngine extends ThreadedLevelLightEngine { + + private static final ProcessorMailbox MAILBOX = ProcessorMailbox.create(task -> { + }, "fawe-no-op"); + private static final ProcessorHandle> HANDLE = ProcessorHandle.of("fawe-no-op", m -> { + }); + + public NoOpLightEngine(final ServerChunkCache chunkProvider) { + super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE); + } + + @Override + public CompletableFuture lightChunk(final ChunkAccess chunk, final boolean excludeBlocks) { + return CompletableFuture.completedFuture(chunk); + } + + } + +} diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index dfcae5783..272d3c84f 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -206,7 +206,7 @@ tasks { versionNumber.set("${project.version}") versionType.set("release") uploadFile.set(file("build/libs/${rootProject.name}-Bukkit-${project.version}.jar")) - gameVersions.addAll(listOf("1.20.2", "1.20.1", "1.20", "1.19.4", "1.18.2", "1.17.1")) + gameVersions.addAll(listOf("1.20.4", "1.20.3", "1.20.2", "1.20.1", "1.20", "1.19.4", "1.18.2", "1.17.1")) loaders.addAll(listOf("paper", "spigot")) changelog.set("The changelog is available on GitHub: https://github.com/IntellectualSites/" + "FastAsyncWorldEdit/releases/tag/${project.version}") diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java index 55340bb07..237c0b220 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java @@ -86,6 +86,11 @@ public class MultiStageReorder extends AbstractBufferingExtent implements Reorde priorityMap.put(BlockTypes.WHITE_BED, PlacementPriority.LAST); priorityMap.put(BlockTypes.YELLOW_BED, PlacementPriority.LAST); priorityMap.put(BlockTypes.GRASS, PlacementPriority.LAST); + // Keep "grass" for <1.20.3 compat + @SuppressWarnings("deprecation") + BlockType grass = BlockTypes.GRASS; + priorityMap.put(grass, PlacementPriority.LAST); + priorityMap.put(BlockTypes.SHORT_GRASS, PlacementPriority.LAST); priorityMap.put(BlockTypes.TALL_GRASS, PlacementPriority.LAST); priorityMap.put(BlockTypes.ROSE_BUSH, PlacementPriority.LAST); priorityMap.put(BlockTypes.DANDELION, PlacementPriority.LAST); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java index 5ea9aa66e..a1ddb2240 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java @@ -29,6 +29,7 @@ import com.sk89q.worldedit.function.pattern.RandomPattern; import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; /** @@ -103,7 +104,12 @@ public class FloraGenerator implements RegionFunction { */ public static Pattern getTemperatePattern() { RandomPattern pattern = new RandomPattern(); - pattern.add(BlockTypes.GRASS.getDefaultState(), 300); + BlockType grass = BlockTypes.SHORT_GRASS; + if (grass == null) { + // Fallback for <1.20.3 compat + grass = BlockTypes.GRASS; + } + pattern.add(grass.getDefaultState(), 300); pattern.add(BlockTypes.POPPY.getDefaultState(), 5); pattern.add(BlockTypes.DANDELION.getDefaultState(), 5); return pattern; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java index 47905dcd4..4d1bde5f8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java @@ -48,6 +48,7 @@ public final class BlockCategories { public static final BlockCategory BIG_DRIPLEAF_PLACEABLE = get("minecraft:big_dripleaf_placeable"); public static final BlockCategory BIRCH_LOGS = get("minecraft:birch_logs"); public static final BlockCategory BUTTONS = get("minecraft:buttons"); + public static final BlockCategory CAMEL_SAND_STEP_SOUND_BLOCKS = get("minecraft:camel_sand_step_sound_blocks"); public static final BlockCategory CAMPFIRES = get("minecraft:campfires"); public static final BlockCategory CANDLE_CAKES = get("minecraft:candle_cakes"); public static final BlockCategory CANDLES = get("minecraft:candles"); @@ -60,6 +61,7 @@ public final class BlockCategories { public static final BlockCategory COAL_ORES = get("minecraft:coal_ores"); public static final BlockCategory COMBINATION_STEP_SOUND_BLOCKS = get("minecraft:combination_step_sound_blocks"); public static final BlockCategory COMPLETES_FIND_TREE_TUTORIAL = get("minecraft:completes_find_tree_tutorial"); + public static final BlockCategory CONCRETE_POWDER = get("minecraft:concrete_powder"); public static final BlockCategory CONVERTABLE_TO_MUD = get("minecraft:convertable_to_mud"); public static final BlockCategory COPPER_ORES = get("minecraft:copper_ores"); public static final BlockCategory CORAL_BLOCKS = get("minecraft:coral_blocks"); 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 0cd3f55e5..4b3204be4 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 @@ -415,6 +415,8 @@ public final class BlockTypes { @Nullable public static final BlockType CHISELED_BOOKSHELF = init(); @Nullable + public static final BlockType CHISELED_COPPER = init(); + @Nullable public static final BlockType CHISELED_DEEPSLATE = init(); @Nullable public static final BlockType CHISELED_NETHER_BRICKS = init(); @@ -429,6 +431,10 @@ public final class BlockTypes { @Nullable public static final BlockType CHISELED_STONE_BRICKS = init(); @Nullable + public static final BlockType CHISELED_TUFF = init(); + @Nullable + public static final BlockType CHISELED_TUFF_BRICKS = init(); + @Nullable public static final BlockType CHORUS_FLOWER = init(); @Nullable public static final BlockType CHORUS_PLANT = init(); @@ -471,6 +477,12 @@ public final class BlockTypes { @Nullable public static final BlockType COPPER_BLOCK = init(); @Nullable + public static final BlockType COPPER_BULB = init(); + @Nullable + public static final BlockType COPPER_DOOR = init(); + @Nullable + public static final BlockType COPPER_GRATE = init(); + @Nullable public static final BlockType CORNFLOWER = init(); @Nullable public static final BlockType CRACKED_DEEPSLATE_BRICKS = init(); @@ -673,6 +685,8 @@ public final class BlockTypes { @Nullable public static final BlockType DEEPSLATE_COPPER_ORE = init(); @Nullable + public static final BlockType COPPER_TRAPDOOR = init(); + @Nullable public static final BlockType DEEPSLATE_DIAMOND_ORE = init(); @Nullable public static final BlockType DEEPSLATE_EMERALD_ORE = init(); @@ -733,6 +747,8 @@ public final class BlockTypes { @Nullable public static final BlockType ENDER_CHEST = init(); @Nullable + public static final BlockType EXPOSED_CHISELED_COPPER = init(); + @Nullable public static final BlockType END_GATEWAY = init(); @Nullable public static final BlockType END_PORTAL = init(); @@ -753,6 +769,14 @@ public final class BlockTypes { @Nullable public static final BlockType EXPOSED_COPPER = init(); @Nullable + public static final BlockType EXPOSED_COPPER_BULB = init(); + @Nullable + public static final BlockType EXPOSED_COPPER_DOOR = init(); + @Nullable + public static final BlockType EXPOSED_COPPER_GRATE = init(); + @Nullable + public static final BlockType EXPOSED_COPPER_TRAPDOOR = init(); + @Nullable public static final BlockType EXPOSED_CUT_COPPER = init(); @Nullable public static final BlockType EXPOSED_CUT_COPPER_SLAB = init(); @@ -808,7 +832,7 @@ public final class BlockTypes { public static final BlockType GRANITE_STAIRS = init(); @Nullable public static final BlockType GRANITE_WALL = init(); - @Nullable + @Nullable @Deprecated public static final BlockType GRASS = init(); @Nullable public static final BlockType GRASS_BLOCK = init(); @@ -901,6 +925,8 @@ public final class BlockTypes { @Nullable public static final BlockType INFESTED_CRACKED_STONE_BRICKS = init(); @Nullable + public static final BlockType CRAFTER = init(); + @Nullable public static final BlockType INFESTED_DEEPSLATE = init(); @Nullable public static final BlockType INFESTED_MOSSY_STONE_BRICKS = init(); @@ -1293,8 +1319,18 @@ public final class BlockTypes { @Nullable public static final BlockType OXEYE_DAISY = init(); @Nullable + public static final BlockType OXIDIZED_CHISELED_COPPER = init(); + @Nullable public static final BlockType OXIDIZED_COPPER = init(); @Nullable + public static final BlockType OXIDIZED_COPPER_BULB = init(); + @Nullable + public static final BlockType OXIDIZED_COPPER_DOOR = init(); + @Nullable + public static final BlockType OXIDIZED_COPPER_GRATE = init(); + @Nullable + public static final BlockType OXIDIZED_COPPER_TRAPDOOR = init(); + @Nullable public static final BlockType OXIDIZED_CUT_COPPER = init(); @Nullable public static final BlockType OXIDIZED_CUT_COPPER_SLAB = init(); @@ -1411,6 +1447,14 @@ public final class BlockTypes { @Nullable public static final BlockType POLISHED_GRANITE_STAIRS = init(); @Nullable + public static final BlockType POLISHED_TUFF = init(); + @Nullable + public static final BlockType POLISHED_TUFF_SLAB = init(); + @Nullable + public static final BlockType POLISHED_TUFF_STAIRS = init(); + @Nullable + public static final BlockType POLISHED_TUFF_WALL = init(); + @Nullable public static final BlockType POPPY = init(); @Nullable public static final BlockType POTATOES = init(); @@ -1667,6 +1711,8 @@ public final class BlockTypes { @Nullable public static final BlockType SEAGRASS = init(); @Nullable + public static final BlockType SHORT_GRASS = init(); + @Nullable public static final BlockType SEA_LANTERN = init(); @Nullable public static final BlockType SEA_PICKLE = init(); @@ -1874,6 +1920,8 @@ public final class BlockTypes { @Nullable public static final BlockType TRAPPED_CHEST = init(); @Nullable + public static final BlockType TRIAL_SPAWNER = init(); + @Nullable public static final BlockType TRIPWIRE = init(); @Nullable public static final BlockType TRIPWIRE_HOOK = init(); @@ -1888,6 +1936,20 @@ public final class BlockTypes { @Nullable public static final BlockType TUFF = init(); @Nullable + public static final BlockType TUFF_BRICK_SLAB = init(); + @Nullable + public static final BlockType TUFF_BRICK_STAIRS = init(); + @Nullable + public static final BlockType TUFF_BRICK_WALL = init(); + @Nullable + public static final BlockType TUFF_BRICKS = init(); + @Nullable + public static final BlockType TUFF_SLAB = init(); + @Nullable + public static final BlockType TUFF_STAIRS = init(); + @Nullable + public static final BlockType TUFF_WALL = init(); + @Nullable public static final BlockType TURTLE_EGG = init(); @Nullable public static final BlockType TWISTING_VINES = init(); @@ -1947,16 +2009,36 @@ public final class BlockTypes { @Nullable public static final BlockType WATER_CAULDRON = init(); @Nullable + public static final BlockType WAXED_CHISELED_COPPER = init(); + @Nullable public static final BlockType WAXED_COPPER_BLOCK = init(); @Nullable + public static final BlockType WAXED_COPPER_BULB = init(); + @Nullable + public static final BlockType WAXED_COPPER_DOOR = init(); + @Nullable + public static final BlockType WAXED_COPPER_GRATE = init(); + @Nullable + public static final BlockType WAXED_COPPER_TRAPDOOR = init(); + @Nullable public static final BlockType WAXED_CUT_COPPER = init(); @Nullable public static final BlockType WAXED_CUT_COPPER_SLAB = init(); @Nullable public static final BlockType WAXED_CUT_COPPER_STAIRS = init(); + @ Nullable + public static final BlockType WAXED_EXPOSED_CHISELED_COPPER = init(); @Nullable public static final BlockType WAXED_EXPOSED_COPPER = init(); @Nullable + public static final BlockType WAXED_EXPOSED_COPPER_BULB = init(); + @Nullable + public static final BlockType WAXED_EXPOSED_COPPER_DOOR = init(); + @Nullable + public static final BlockType WAXED_EXPOSED_COPPER_GRATE = init(); + @Nullable + public static final BlockType WAXED_EXPOSED_COPPER_TRAPDOOR = init(); + @Nullable public static final BlockType WAXED_EXPOSED_CUT_COPPER = init(); @Nullable public static final BlockType WAXED_EXPOSED_CUT_COPPER_SLAB = init(); @@ -1965,22 +2047,52 @@ public final class BlockTypes { @Nullable public static final BlockType WAXED_OXIDIZED_COPPER = init(); @Nullable + public static final BlockType WAXED_OXIDIZED_COPPER_BULB = init(); + @Nullable + public static final BlockType WAXED_OXIDIZED_COPPER_DOOR = init(); + @Nullable + public static final BlockType WAXED_OXIDIZED_COPPER_GRATE = init(); + @Nullable + public static final BlockType WAXED_OXIDIZED_COPPER_TRAPDOOR = init(); + @Nullable + public static final BlockType WAXED_OXIDIZED_CHISELED_COPPER = init(); + @Nullable public static final BlockType WAXED_OXIDIZED_CUT_COPPER = init(); @Nullable public static final BlockType WAXED_OXIDIZED_CUT_COPPER_SLAB = init(); @Nullable public static final BlockType WAXED_OXIDIZED_CUT_COPPER_STAIRS = init(); @Nullable + public static final BlockType WAXED_WEATHERED_CHISELED_COPPER = init(); + @Nullable public static final BlockType WAXED_WEATHERED_COPPER = init(); @Nullable + public static final BlockType WAXED_WEATHERED_COPPER_BULB = init(); + @Nullable + public static final BlockType WAXED_WEATHERED_COPPER_DOOR = init(); + @Nullable + public static final BlockType WAXED_WEATHERED_COPPER_GRATE = init(); + @Nullable + public static final BlockType WAXED_WEATHERED_COPPER_TRAPDOOR = init(); + @Nullable public static final BlockType WAXED_WEATHERED_CUT_COPPER = init(); @Nullable public static final BlockType WAXED_WEATHERED_CUT_COPPER_SLAB = init(); @Nullable public static final BlockType WAXED_WEATHERED_CUT_COPPER_STAIRS = init(); @Nullable + public static final BlockType WEATHERED_CHISELED_COPPER = init(); + @Nullable public static final BlockType WEATHERED_COPPER = init(); @Nullable + public static final BlockType WEATHERED_COPPER_BULB = init(); + @Nullable + public static final BlockType WEATHERED_COPPER_DOOR = init(); + @Nullable + public static final BlockType WEATHERED_COPPER_GRATE = init(); + @Nullable + public static final BlockType WEATHERED_COPPER_TRAPDOOR = init(); + @Nullable public static final BlockType WEATHERED_CUT_COPPER = init(); @Nullable public static final BlockType WEATHERED_CUT_COPPER_SLAB = init(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java index 4b650ac07..f981593fe 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java @@ -51,6 +51,8 @@ public final class EntityTypes { @Nullable public static final EntityType BOAT = get("minecraft:boat"); @Nullable + public static final EntityType BREEZE = get("minecraft:breeze"); + @Nullable public static final EntityType CAMEL = get("minecraft:camel"); @Nullable public static final EntityType CAT = get("minecraft:cat"); @@ -259,6 +261,8 @@ public final class EntityTypes { @Nullable public static final EntityType WARDEN = get("minecraft:warden"); @Nullable + public static final EntityType WIND_CHARGE = get("minecraft:wind_charge"); + @Nullable public static final EntityType WITCH = get("minecraft:witch"); @Nullable public static final EntityType WITHER = get("minecraft:wither"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java index 663cf5c61..b8064bb94 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java @@ -319,6 +319,8 @@ public final class ItemTypes { @Nullable public static final ItemType BREAD = init(); @Nullable + public static final ItemType BREEZE_SPAWN_EGG = init(); + @Nullable public static final ItemType BREWER_POTTERY_SHERD = init(); @Nullable public static final ItemType BREWING_STAND = init(); @@ -468,6 +470,8 @@ public final class ItemTypes { @Nullable public static final ItemType CHISELED_BOOKSHELF = init(); @Nullable + public static final ItemType CHISELED_COPPER = init(); + @Nullable public static final ItemType CHISELED_DEEPSLATE = init(); @Nullable public static final ItemType CHISELED_NETHER_BRICKS = init(); @@ -482,6 +486,10 @@ public final class ItemTypes { @Nullable public static final ItemType CHISELED_STONE_BRICKS = init(); @Nullable + public static final ItemType CHISELED_TUFF = init(); + @Nullable + public static final ItemType CHISELED_TUFF_BRICKS = init(); + @Nullable public static final ItemType CHORUS_FLOWER = init(); @Nullable public static final ItemType CHORUS_FRUIT = init(); @@ -560,10 +568,18 @@ public final class ItemTypes { @Nullable public static final ItemType COPPER_BLOCK = init(); @Nullable + public static final ItemType COPPER_BULB = init(); + @Nullable + public static final ItemType COPPER_DOOR = init(); + @Nullable + public static final ItemType COPPER_GRATE = init(); + @Nullable public static final ItemType COPPER_INGOT = init(); @Nullable public static final ItemType COPPER_ORE = init(); @Nullable + public static final ItemType COPPER_TRAPDOOR = init(); + @Nullable public static final ItemType CORNFLOWER = init(); @Nullable public static final ItemType COW_SPAWN_EGG = init(); @@ -578,6 +594,8 @@ public final class ItemTypes { @Nullable public static final ItemType CRACKED_STONE_BRICKS = init(); @Nullable + public static final ItemType CRAFTER = init(); + @Nullable public static final ItemType CRAFTING_TABLE = init(); @Nullable public static final ItemType CREEPER_BANNER_PATTERN = init(); @@ -903,8 +921,18 @@ public final class ItemTypes { @Nullable public static final ItemType EXPLORER_POTTERY_SHERD = init(); @Nullable + public static final ItemType EXPOSED_CHISELED_COPPER = init(); + @Nullable public static final ItemType EXPOSED_COPPER = init(); @Nullable + public static final ItemType EXPOSED_COPPER_BULB = init(); + @Nullable + public static final ItemType EXPOSED_COPPER_DOOR = init(); + @Nullable + public static final ItemType EXPOSED_COPPER_GRATE = init(); + @Nullable + public static final ItemType EXPOSED_COPPER_TRAPDOOR = init(); + @Nullable public static final ItemType EXPOSED_CUT_COPPER = init(); @Nullable public static final ItemType EXPOSED_CUT_COPPER_SLAB = init(); @@ -1036,7 +1064,7 @@ public final class ItemTypes { public static final ItemType GRANITE_STAIRS = init(); @Nullable public static final ItemType GRANITE_WALL = init(); - @Nullable + @Nullable @Deprecated public static final ItemType GRASS = init(); @Nullable public static final ItemType GRASS_BLOCK = init(); @@ -1670,8 +1698,18 @@ public final class ItemTypes { @Nullable public static final ItemType OXEYE_DAISY = init(); @Nullable + public static final ItemType OXIDIZED_CHISELED_COPPER = init(); + @Nullable public static final ItemType OXIDIZED_COPPER = init(); @Nullable + public static final ItemType OXIDIZED_COPPER_BULB = init(); + @Nullable + public static final ItemType OXIDIZED_COPPER_DOOR = init(); + @Nullable + public static final ItemType OXIDIZED_COPPER_GRATE = init(); + @Nullable + public static final ItemType OXIDIZED_COPPER_TRAPDOOR = init(); + @Nullable public static final ItemType OXIDIZED_CUT_COPPER = init(); @Nullable public static final ItemType OXIDIZED_CUT_COPPER_SLAB = init(); @@ -1808,6 +1846,14 @@ public final class ItemTypes { @Nullable public static final ItemType POLISHED_GRANITE_STAIRS = init(); @Nullable + public static final ItemType POLISHED_TUFF = init(); + @Nullable + public static final ItemType POLISHED_TUFF_SLAB = init(); + @Nullable + public static final ItemType POLISHED_TUFF_STAIRS = init(); + @Nullable + public static final ItemType POLISHED_TUFF_WALL = init(); + @Nullable public static final ItemType POPPED_CHORUS_FRUIT = init(); @Nullable public static final ItemType POPPY = init(); @@ -2061,6 +2107,8 @@ public final class ItemTypes { @Nullable public static final ItemType SHIELD = init(); @Nullable + public static final ItemType SHORT_GRASS = init(); + @Nullable public static final ItemType SHROOMLIGHT = init(); @Nullable public static final ItemType SHULKER_BOX = init(); @@ -2336,6 +2384,10 @@ public final class ItemTypes { @Nullable public static final ItemType TRAPPED_CHEST = init(); @Nullable + public static final ItemType TRIAL_KEY = init(); + @Nullable + public static final ItemType TRIAL_SPAWNER = init(); + @Nullable public static final ItemType TRIDENT = init(); @Nullable public static final ItemType TRIPWIRE_HOOK = init(); @@ -2354,6 +2406,20 @@ public final class ItemTypes { @Nullable public static final ItemType TUFF = init(); @Nullable + public static final ItemType TUFF_BRICK_SLAB = init(); + @Nullable + public static final ItemType TUFF_BRICK_STAIRS = init(); + @Nullable + public static final ItemType TUFF_BRICK_WALL = init(); + @Nullable + public static final ItemType TUFF_BRICKS = init(); + @Nullable + public static final ItemType TUFF_SLAB = init(); + @Nullable + public static final ItemType TUFF_STAIRS = init(); + @Nullable + public static final ItemType TUFF_WALL = init(); + @Nullable public static final ItemType TURTLE_EGG = init(); @Nullable public static final ItemType TURTLE_HELMET = init(); @@ -2418,32 +2484,72 @@ public final class ItemTypes { @Nullable public static final ItemType WATER_BUCKET = init(); @Nullable + public static final ItemType WAXED_CHISELED_COPPER = init(); + @Nullable public static final ItemType WAXED_COPPER_BLOCK = init(); @Nullable + public static final ItemType WAXED_COPPER_BULB = init(); + @Nullable + public static final ItemType WAXED_COPPER_DOOR = init(); + @Nullable + public static final ItemType WAXED_COPPER_GRATE = init(); + @Nullable + public static final ItemType WAXED_COPPER_TRAPDOOR = init(); + @Nullable public static final ItemType WAXED_CUT_COPPER = init(); @Nullable public static final ItemType WAXED_CUT_COPPER_SLAB = init(); @Nullable public static final ItemType WAXED_CUT_COPPER_STAIRS = init(); @Nullable + public static final ItemType WAXED_EXPOSED_CHISELED_COPPER = init(); + @Nullable public static final ItemType WAXED_EXPOSED_COPPER = init(); @Nullable + public static final ItemType WAXED_EXPOSED_COPPER_BULB = init(); + @Nullable + public static final ItemType WAXED_EXPOSED_COPPER_DOOR = init(); + @Nullable + public static final ItemType WAXED_EXPOSED_COPPER_GRATE = init(); + @Nullable + public static final ItemType WAXED_EXPOSED_COPPER_TRAPDOOR = init(); + @Nullable public static final ItemType WAXED_EXPOSED_CUT_COPPER = init(); @Nullable public static final ItemType WAXED_EXPOSED_CUT_COPPER_SLAB = init(); @Nullable public static final ItemType WAXED_EXPOSED_CUT_COPPER_STAIRS = init(); @Nullable + public static final ItemType WAXED_OXIDIZED_CHISELED_COPPER = init(); + @Nullable public static final ItemType WAXED_OXIDIZED_COPPER = init(); @Nullable + public static final ItemType WAXED_OXIDIZED_COPPER_BULB = init(); + @Nullable + public static final ItemType WAXED_OXIDIZED_COPPER_DOOR = init(); + @Nullable + public static final ItemType WAXED_OXIDIZED_COPPER_GRATE = init(); + @Nullable + public static final ItemType WAXED_OXIDIZED_COPPER_TRAPDOOR = init(); + @Nullable public static final ItemType WAXED_OXIDIZED_CUT_COPPER = init(); @Nullable public static final ItemType WAXED_OXIDIZED_CUT_COPPER_SLAB = init(); @Nullable public static final ItemType WAXED_OXIDIZED_CUT_COPPER_STAIRS = init(); @Nullable + public static final ItemType WAXED_WEATHERED_CHISELED_COPPER = init(); + @Nullable public static final ItemType WAXED_WEATHERED_COPPER = init(); @Nullable + public static final ItemType WAXED_WEATHERED_COPPER_BULB = init(); + @Nullable + public static final ItemType WAXED_WEATHERED_COPPER_DOOR = init(); + @Nullable + public static final ItemType WAXED_WEATHERED_COPPER_GRATE = init(); + @Nullable + public static final ItemType WAXED_WEATHERED_COPPER_TRAPDOOR = init(); + @Nullable public static final ItemType WAXED_WEATHERED_CUT_COPPER = init(); @Nullable public static final ItemType WAXED_WEATHERED_CUT_COPPER_SLAB = init(); @@ -2452,8 +2558,18 @@ public final class ItemTypes { @Nullable public static final ItemType WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE = init(); @Nullable + public static final ItemType WEATHERED_CHISELED_COPPER = init(); + @Nullable public static final ItemType WEATHERED_COPPER = init(); @Nullable + public static final ItemType WEATHERED_COPPER_BULB = init(); + @Nullable + public static final ItemType WEATHERED_COPPER_DOOR = init(); + @Nullable + public static final ItemType WEATHERED_COPPER_GRATE = init(); + @Nullable + public static final ItemType WEATHERED_COPPER_TRAPDOOR = init(); + @Nullable public static final ItemType WEATHERED_CUT_COPPER = init(); @Nullable public static final ItemType WEATHERED_CUT_COPPER_SLAB = init(); From 8496ddf5b87532475ceab4664df10c11ddba9dae Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Fri, 8 Dec 2023 07:37:23 +0100 Subject: [PATCH 087/466] Release 2.8.3 --- build.gradle.kts | 2 +- worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts | 2 +- worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts | 2 +- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 390870651..a45dc3e4c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s-%s", rootVersion, buildNumber) +version = String.format("%s", rootVersion) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") diff --git a/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts index 20bff7359..227eee362 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ - the().paperDevBundle("1.20.1-R0.1-20230916.212543-167") + the().paperDevBundle("1.20.1-R0.1-20230921.165944-178") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts index 70c495b7b..3b08adfe8 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ - the().paperDevBundle("1.20.2-R0.1-20231125.095734-103") + the().paperDevBundle("1.20.2-R0.1-20231203.034718-121") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index befcb5705..34dda434a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ - the().paperDevBundle("1.20.3-R0.1-20231207.043048-3") + the().paperDevBundle("1.20.4-R0.1-20231207.202833-1") compileOnly(libs.paperlib) } From 6d295bde9a85933c6a740bd21f150ec5577ad893 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Fri, 8 Dec 2023 07:48:14 +0100 Subject: [PATCH 088/466] Back to snapshot for development --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index a45dc3e4c..8d8f75c3c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.8.3") +var rootVersion by extra("2.8.4") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s", rootVersion) +version = String.format("%s-%s", rootVersion, buildNumber) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From 026b2eca9c83fe558981b973f2a4782217270ec3 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Fri, 8 Dec 2023 16:26:06 +0100 Subject: [PATCH 089/466] Update Paperweight --- .../bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java index 2dc7d4b2b..899c6e0c4 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java @@ -181,8 +181,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter Date: Fri, 8 Dec 2023 16:30:22 +0100 Subject: [PATCH 090/466] Update dependency com.modrinth.minotaur to v2.8.7 (#2513) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5ac2c2ab9..9cfc77234 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -50,7 +50,7 @@ mockito = "5.8.0" # Gradle plugins pluginyml = "0.6.0" -minotaur = "2.8.6" +minotaur = "2.8.7" [libraries] # Minecraft expectations From 4c3dd9accfbc5cb228897d991564b29a536ded1c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 8 Dec 2023 16:30:31 +0100 Subject: [PATCH 091/466] Update dependency io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin to v1.5.10 (#2514) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index a65407ce5..8b4b57369 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -24,7 +24,7 @@ dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.2.1") implementation("com.github.johnrengelman:shadow:8.1.1") - implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.5") + implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.10") } kotlin { From fe626a92e14ec1fb9db38a52895c131c9230443b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 8 Dec 2023 16:30:50 +0100 Subject: [PATCH 092/466] Update dependency org.checkerframework:checker-qual to v3.41.0 (#2515) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9cfc77234..189057a75 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.14.0" adventure-bukkit = "4.3.1" -checkerqual = "3.40.0" +checkerqual = "3.41.0" truezip = "6.8.4" auto-value = "1.10.4" findbugs = "3.0.2" From d4b68b384bf7d5d1baa82ec7a023b371ec550ec9 Mon Sep 17 00:00:00 2001 From: Jordan Date: Tue, 12 Dec 2023 07:00:40 +0000 Subject: [PATCH 093/466] fix: add chunk loc to tile entity location when trimming (#2500) - fixes #2499 --- .../core/extent/HeightBoundExtent.java | 6 ++--- .../core/queue/IBatchProcessor.java | 22 +++++++++++++++++++ .../fastasyncworldedit/core/queue/IChunk.java | 11 ++++++++++ .../sk89q/worldedit/regions/CuboidRegion.java | 14 +++++++----- .../com/sk89q/worldedit/regions/Region.java | 6 +++-- 5 files changed, 48 insertions(+), 11 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HeightBoundExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HeightBoundExtent.java index ff57e00da..c22d9e6be 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HeightBoundExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HeightBoundExtent.java @@ -6,12 +6,11 @@ import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.regions.RegionWrapper; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import java.util.Collection; import java.util.Collections; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; public class HeightBoundExtent extends FaweRegionExtent { @@ -50,7 +49,8 @@ public class HeightBoundExtent extends FaweRegionExtent { @Override public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { - if (trimY(set, min, max, true) | trimNBT(set, this::contains)) { + BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0); + if (trimY(set, min, max, true) | trimNBT(set, this::contains, pos -> this.contains(pos.add(chunkPos)))) { return set; } return null; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java index 5eeafe28e..b096b93fe 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java @@ -155,7 +155,9 @@ public interface IBatchProcessor { * Utility method to trim entity and blocks with a provided contains function. * * @return false if chunk is empty of NBT + * @deprecated tiles are stored in chunk-normalised coordinate space and thus cannot use the same function as entities */ + @Deprecated(forRemoval = true, since = "TODO") default boolean trimNBT(IChunkSet set, Function contains) { Set ents = set.getEntities(); if (!ents.isEmpty()) { @@ -169,6 +171,26 @@ public interface IBatchProcessor { return !tiles.isEmpty() || !ents.isEmpty(); } + /** + * Utility method to trim entity and blocks with a provided contains function. + * + * @return false if chunk is empty of NBT + * @since TODO + */ + default boolean trimNBT( + IChunkSet set, Function containsEntity, Function containsTile + ) { + Set ents = set.getEntities(); + if (!ents.isEmpty()) { + ents.removeIf(ent -> !containsEntity.apply(ent.getEntityPosition().toBlockPoint())); + } + Map tiles = set.getTiles(); + if (!tiles.isEmpty()) { + tiles.entrySet().removeIf(blockVector3CompoundTagEntry -> !containsTile.apply(blockVector3CompoundTagEntry.getKey())); + } + return !tiles.isEmpty() || !ents.isEmpty(); + } + /** * Join two processors and return the result. */ diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunk.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunk.java index 0acfa4a22..5a03a9987 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunk.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunk.java @@ -1,6 +1,7 @@ package com.fastasyncworldedit.core.queue; import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import javax.annotation.Nullable; @@ -33,6 +34,16 @@ public interface IChunk extends Trimable, IChunkGet, IChunkSet { */ int getZ(); + /** + * Return the minimum block coordinate of the chunk + * + * @return BlockVector3 of minimum block coordinate + * @since TODO + */ + default BlockVector3 getChunkBlockCoord() { + return BlockVector3.at(getX() << 4, getMinY(), getZ() << 4); + } + /** * If the chunk is a delegate, returns its parent's root * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index cc2f03aa2..d04e5aa8c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -22,7 +22,6 @@ package com.sk89q.worldedit.regions; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock; import com.fastasyncworldedit.core.math.BlockVectorSet; -import com.fastasyncworldedit.core.math.MutableBlockVector2; import com.fastasyncworldedit.core.math.MutableBlockVector3; import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.IChunk; @@ -805,7 +804,8 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return set; } trimY(set, minY, maxY, true); - trimNBT(set, this::contains); + BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0); + trimNBT(set, this::contains, pos -> this.contains(pos.add(chunkPos))); return set; } if (tx >= minX && bx <= maxX && tz >= minZ && bz <= maxZ) { @@ -868,8 +868,8 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { } set.setBlocks(layer, arr); } - - trimNBT(set, this::contains); + final BlockVector3 chunkPos = BlockVector3.at(chunk.getX() << 4, 0, chunk.getZ() << 4); + trimNBT(set, this::contains, pos -> this.contains(pos.add(chunkPos))); return set; } return null; @@ -893,7 +893,8 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return null; } trimY(set, minY, maxY, false); - trimNBT(set, this::contains); + BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0); + trimNBT(set, this::contains, pos -> this.contains(pos.add(chunkPos))); return set; } if (tx >= minX && bx <= maxX && tz >= minZ && bz <= maxZ) { @@ -943,7 +944,8 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { } set.setBlocks(layer, arr); } - trimNBT(set, bv3 -> !this.contains(bv3)); + BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0); + trimNBT(set, bv3 -> !this.contains(bv3), bv3 -> !this.contains(bv3.add(chunkPos))); return set; } return set; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java index b89536520..d2fa35310 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java @@ -425,7 +425,8 @@ public interface Region extends Iterable, Cloneable, IBatchProcess } } if (processExtra) { - trimNBT(set, this::contains); + BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0); + trimNBT(set, this::contains, pos -> this.contains(pos.add(chunkPos))); } return set; } else { @@ -477,7 +478,8 @@ public interface Region extends Iterable, Cloneable, IBatchProcess } } if (processExtra) { - trimNBT(set, bv3 -> !this.contains(bv3)); + BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0); + trimNBT(set, bv3 -> !this.contains(bv3), bv3 -> !this.contains(bv3.add(chunkPos))); } return set; } else { From d4d7cb03861decf1287a97396513b0f95d5efc20 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 16 Dec 2023 22:40:32 +0100 Subject: [PATCH 094/466] Update plotsquared to v7.2.1 (#2520) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 189057a75..50b96e690 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ griefprevention = "16.18.1" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" towny = "0.100.0.8" -plotsquared = "7.2.0" +plotsquared = "7.2.1" # Third party bstats = "3.0.2" From 0d35cfb6b30665c740bbba1feb6d0bc92e3e8d82 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 16 Dec 2023 22:40:44 +0100 Subject: [PATCH 095/466] Update dependency org.checkerframework:checker-qual to v3.42.0 (#2521) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 50b96e690..c8d3867ad 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.14.0" adventure-bukkit = "4.3.1" -checkerqual = "3.41.0" +checkerqual = "3.42.0" truezip = "6.8.4" auto-value = "1.10.4" findbugs = "3.0.2" From 885df021c1a0f4e87ad67f59f43525e8a8508e2e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 16 Dec 2023 22:42:42 +0100 Subject: [PATCH 096/466] Update github/codeql-action action to v3 (#2523) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 8dd831550..b7e9c61ed 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -27,10 +27,10 @@ jobs: cache: gradle java-version: 17 - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 From 17abaeb19e1932b364151d3bbdf1eb0bd9340f7d Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sat, 16 Dec 2023 22:45:30 +0100 Subject: [PATCH 097/466] Update paper --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c8d3867ad..57aaf1fcf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] # Minecraft expectations -paper = "1.20.2-R0.1-SNAPSHOT" +paper = "1.20.4-R0.1-SNAPSHOT" fastutil = "8.5.9" guava = "31.1-jre" log4j = "2.19.0" From f44b1b48c7cca1ab1e7a118e479209cd956b9e85 Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 18 Dec 2023 14:58:53 +0000 Subject: [PATCH 098/466] chore: add a more informative error when parsing block properties (#2524) --- .../worldedit/world/block/BlockState.java | 27 ++++++++++++++++--- .../src/main/resources/lang/strings.json | 1 + 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index f08675fc5..5059c737a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -178,9 +178,18 @@ public class BlockState implements BlockStateHolder, Pattern { String name = property.getName(); charSequence.setSubstring(propStrStart + name.length() + 2, state.length() - 1); - int index = charSequence.length() <= 0 ? -1 : property.getIndexFor(charSequence); - if (index != -1) { - return type.withPropertyId(index); + try { + int index = charSequence.length() <= 0 ? -1 : property.getIndexFor(charSequence); + if (index != -1) { + return type.withPropertyId(index); + } + } catch (Exception e) { + throw new InputParseException(Caption.of( + "fawe.error.invalid-block-state-property", + TextComponent.of(charSequence.toString()), + TextComponent.of(name), + TextComponent.of(state) + ), e); } } int stateId; @@ -200,7 +209,17 @@ public class BlockState implements BlockStateHolder, Pattern { case ',': { charSequence.setSubstring(last, i); if (property != null) { - int index = property.getIndexFor(charSequence); + int index; + try { + index = property.getIndexFor(charSequence); + } catch (Exception e) { + throw new InputParseException(Caption.of( + "fawe.error.invalid-block-state-property", + TextComponent.of(charSequence.toString()), + TextComponent.of(property.getName()), + TextComponent.of(state) + ), e); + } if (index == -1) { throw SuggestInputParseException.of(charSequence.toString(), (List) property.getValues()); } diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index d702ead53..3d1295ab0 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -92,6 +92,7 @@ "fawe.error.parser.invalid-data": "Invalid data: {0}", "fawe.error.unsupported": "Unsupported!", "fawe.error.invalid-block-type": "Does not match a valid block type: {0}", + "fawe.error.invalid-block-state-property": "Cannot parse value `{0}` for property `{1}`, block state: `{2}`", "fawe.error.nbt.forbidden": "You are not allowed to use nbt. Lacking permission: {0}", "fawe.error.invalid-arguments": "Invalid amount of arguments. Expected: {0}", "fawe.error.unrecognised-tag": "Unrecognised tag: {0} {1}", From 6caf4640ea85fdfbd883b12986246c0409beaab4 Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 18 Dec 2023 15:04:34 +0000 Subject: [PATCH 099/466] feat: add config option for if the DOC should lock the file channel (#2526) - related to #2222 - effectively just a workaround as most people would not need to worry about locking the clipboard file --- .../core/configuration/Settings.java | 7 ++++ .../clipboard/DiskOptimizedClipboard.java | 32 ++++++++++--------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index 099386f00..009958270 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -721,6 +721,13 @@ public class Settings extends Config { " - Requires clipboard.use-disk to be enabled" }) public boolean SAVE_CLIPBOARD_NBT_TO_DISK = true; + @Comment({ + "Apply a file lock on the clipboard file (only relevant if clipboad.on-disk is enabled)", + " - Prevents other processes using the file whilst in use by FAWE", + " - This extends to other servers, useful if you have multiple servers using a unified clipboard folder", + " - May run into issues where a file lock is not correctly lifted" + }) + public boolean LOCK_CLIPBOARD_FILE = false; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java index 3f7c746c3..76f22a194 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java @@ -305,22 +305,24 @@ public class DiskOptimizedClipboard extends LinearClipboard { private void init() throws IOException { if (this.fileChannel == null) { this.fileChannel = braf.getChannel(); - try { - FileLock lock = this.fileChannel.lock(); - LOCK_HOLDER_CACHE.put(file.getName(), new LockHolder(lock)); - } catch (OverlappingFileLockException e) { - LockHolder existing = LOCK_HOLDER_CACHE.get(file.getName()); - if (existing != null) { - long ms = System.currentTimeMillis() - existing.lockHeldSince; - LOGGER.error( - "Cannot lock clipboard file {} acquired by thread {}, {}ms ago", - file.getName(), - existing.thread, - ms - ); + if (Settings.settings().CLIPBOARD.LOCK_CLIPBOARD_FILE) { + try { + FileLock lock = this.fileChannel.lock(); + LOCK_HOLDER_CACHE.put(file.getName(), new LockHolder(lock)); + } catch (OverlappingFileLockException e) { + LockHolder existing = LOCK_HOLDER_CACHE.get(file.getName()); + if (existing != null) { + long ms = System.currentTimeMillis() - existing.lockHeldSince; + LOGGER.error( + "Cannot lock clipboard file {} acquired by thread {}, {}ms ago", + file.getName(), + existing.thread, + ms + ); + } + // Rethrow to prevent clipboard access + throw e; } - // Rethrow to prevent clipboard access - throw e; } this.byteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, braf.length()); } From 2f92626433945cb8c810f4fcacc5bb20311eaa05 Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 18 Dec 2023 15:33:02 +0000 Subject: [PATCH 100/466] feat: add switch to allow removal of entities on paste (#2525) - closes #2395 --- .../worldedit/command/ClipboardCommands.java | 56 +++++++++++++------ 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index 8ccd4f44e..177366651 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 @@ -47,6 +47,7 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.annotation.Confirm; import com.sk89q.worldedit.command.util.annotation.Preload; +import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; @@ -70,6 +71,7 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.NullRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionIntersection; @@ -453,7 +455,9 @@ public class ClipboardCommands { @Switch(name = 'e', desc = "Paste entities if available") boolean pasteEntities, @Switch(name = 'b', desc = "Paste biomes if available") - boolean pasteBiomes + boolean pasteBiomes, + @Switch(name = 'x', desc = "Remove existing entities in the affected region") + boolean removeEntities ) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); final Clipboard clipboard = holder.getClipboard(); @@ -466,17 +470,22 @@ public class ClipboardCommands { } Region region = clipboard.getRegion().clone(); - if (selectPasted || onlySelect) { + if (selectPasted || onlySelect || removeEntities) { BlockVector3 clipboardOffset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin()); BlockVector3 realTo = to.add(holder.getTransform().apply(clipboardOffset.toVector3()).toBlockPoint()); BlockVector3 max = realTo.add(holder .getTransform() .apply(region.getMaximumPoint().subtract(region.getMinimumPoint()).toVector3()) .toBlockPoint()); - RegionSelector selector = new CuboidRegionSelector(world, realTo, max); - session.setRegionSelector(world, selector); - selector.learnChanges(); - selector.explainRegionAdjust(actor, session); + if (removeEntities) { + editSession.getEntities(new CuboidRegion(realTo, max)).forEach(Entity::remove); + } + if (selectPasted || onlySelect) { + RegionSelector selector = new CuboidRegionSelector(world, realTo, max); + session.setRegionSelector(world, selector); + selector.learnChanges(); + selector.explainRegionAdjust(actor, session); + } } if (onlySelect) { actor.print(Caption.of("worldedit.paste.selected")); @@ -513,14 +522,19 @@ public class ClipboardCommands { boolean pasteBiomes, @ArgFlag(name = 'm', desc = "Only paste blocks matching this mask") @ClipboardMask - Mask sourceMask + Mask sourceMask, + //FAWE start - entity removal + @Switch(name = 'x', desc = "Remove existing entities in the affected region") + boolean removeEntities + //FAWE end + ) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); //FAWE start - use place if (holder.getTransform().isIdentity() && sourceMask == null) { place(actor, world, session, editSession, ignoreAirBlocks, atOrigin, selectPasted, onlySelect, - pasteEntities, pasteBiomes + pasteEntities, pasteBiomes, removeEntities ); return; } @@ -547,21 +561,29 @@ public class ClipboardCommands { messages.addAll(Lists.newArrayList(operation.getStatusMessages())); } - if (selectPasted || onlySelect) { + if (selectPasted || onlySelect || removeEntities) { 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())); - final CuboidRegionSelector selector; - if (session.getRegionSelector(world) instanceof ExtendingCuboidRegionSelector) { - selector = new ExtendingCuboidRegionSelector(world, realTo.toBlockPoint(), max.toBlockPoint()); - } else { - selector = new CuboidRegionSelector(world, realTo.toBlockPoint(), max.toBlockPoint()); + + // FAWE start - entity remova;l + if (removeEntities) { + editSession.getEntities(new CuboidRegion(realTo.toBlockPoint(), max.toBlockPoint())).forEach(Entity::remove); + } + if (selectPasted || onlySelect) { + //FAWE end + final CuboidRegionSelector selector; + if (session.getRegionSelector(world) instanceof ExtendingCuboidRegionSelector) { + selector = new ExtendingCuboidRegionSelector(world, realTo.toBlockPoint(), max.toBlockPoint()); + } else { + selector = new CuboidRegionSelector(world, realTo.toBlockPoint(), max.toBlockPoint()); + } + session.setRegionSelector(world, selector); + selector.learnChanges(); + selector.explainRegionAdjust(actor, session); } - session.setRegionSelector(world, selector); - selector.learnChanges(); - selector.explainRegionAdjust(actor, session); } if (onlySelect) { From 28ab5662fdb72f1bf6eb2abbd2127ee24b4e9635 Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 21 Dec 2023 13:11:44 +0000 Subject: [PATCH 101/466] fix: correct the delegated methods in AbstractDelegateExtent (#2365) - Not all methods should be overridden: we need to keep delegating-to-setblock methods in parent classes --- .../extent/AbstractDelegateExtent.java | 108 +++++++++++++++--- 1 file changed, 95 insertions(+), 13 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java index 9dfd373ea..768af09c1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -25,27 +25,34 @@ import com.fastasyncworldedit.core.extent.HistoryExtent; import com.fastasyncworldedit.core.extent.NullExtent; import com.fastasyncworldedit.core.history.changeset.AbstractChangeSet; import com.fastasyncworldedit.core.internal.exception.FaweException; +import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.util.ExtentTraverser; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.buffer.ForgetfulExtentBuffer; +import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.OperationQueue; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Location; 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.block.BlockType; import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; import java.util.List; +import java.util.Set; import java.util.UUID; import static com.google.common.base.Preconditions.checkNotNull; @@ -168,6 +175,7 @@ public class AbstractDelegateExtent implements Extent { } } + //FAWE start @Override public boolean cancel() { ExtentTraverser traverser = new ExtentTraverser<>(this); @@ -188,7 +196,6 @@ public class AbstractDelegateExtent implements Extent { return true; } - //FAWE start @Override public void removeEntity(int x, int y, int z, UUID uuid) { extent.removeEntity(x, y, z, uuid); @@ -225,11 +232,72 @@ public class AbstractDelegateExtent implements Extent { } } + @Override + public boolean isWorld() { + return extent.isWorld(); + } + + @Override + public List> getBlockDistribution(final Region region) { + return extent.getBlockDistribution(region); + } + + @Override + public List> getBlockDistributionWithData(final Region region) { + return extent.getBlockDistributionWithData(region); + } + @Override public int getMaxY() { return extent.getMaxY(); } + @Override + public int countBlocks(final Region region, final Set searchBlocks) { + return extent.countBlocks(region, searchBlocks); + } + + @Override + public int countBlocks(final Region region, final Mask searchMask) { + return extent.countBlocks(region, searchMask); + } + + @Override + public > int setBlocks(final Region region, final B block) throws MaxChangedBlocksException { + return extent.setBlocks(region, block); + } + + @Override + public int setBlocks(final Region region, final Pattern pattern) throws MaxChangedBlocksException { + return extent.setBlocks(region, pattern); + } + + @Override + public > int replaceBlocks( + final Region region, + final Set filter, + final B replacement + ) + throws MaxChangedBlocksException { + return extent.replaceBlocks(region, filter, replacement); + } + + @Override + public int replaceBlocks(final Region region, final Set filter, final Pattern pattern) throws + MaxChangedBlocksException { + return extent.replaceBlocks(region, filter, pattern); + } + + @Override + public int replaceBlocks(final Region region, final Mask mask, final Pattern pattern) throws MaxChangedBlocksException { + return extent.replaceBlocks(region, mask, pattern); + } + + @Override + public int setBlocks(final Set vset, final Pattern pattern) { + return extent.setBlocks(vset, pattern); + } + @Override public int getMinY() { return extent.getMinY(); @@ -295,23 +363,29 @@ public class AbstractDelegateExtent implements Extent { return this; } + @Override + public T apply(final Region region, final T filter, final boolean full) { + return extent.apply(region, filter, full); + } + //FAWE end + protected Operation commitBefore() { return null; } + @Override + public BiomeType getBiome(BlockVector3 position) { + //FAWE start - switch top x,y,z + return extent.getBiomeType(position.getX(), position.getY(), position.getZ()); + //FAWE end + } + + //FAWE start @Override public BiomeType getBiomeType(int x, int y, int z) { return extent.getBiomeType(x, y, z); } - @Override - public BiomeType getBiome(BlockVector3 position) { - return extent.getBiome(position); - } - /* - History - */ - @Override public int getEmittedLight(int x, int y, int z) { return extent.getEmittedLight(x, y, z); @@ -341,13 +415,17 @@ public class AbstractDelegateExtent implements Extent { new ExtentTraverser<>(this).setNext(new HistoryExtent(extent, changeSet)); } } + //FAWE end @Override public > boolean setBlock(BlockVector3 position, T block) throws WorldEditException { + //FAWE start - switch to x,y,z return extent.setBlock(position.getX(), position.getY(), position.getZ(), block); + //FAWE end } + //FAWE start @Override public > boolean setBlock( int x, int y, @@ -360,6 +438,7 @@ public class AbstractDelegateExtent implements Extent { public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { return setBlock(x, y, z, getBlock(x, y, z).toBaseBlock(tile)); } + //FAWE end @Override public boolean fullySupports3DBiomes() { @@ -367,13 +446,16 @@ public class AbstractDelegateExtent implements Extent { } @Override - public boolean setBiome(int x, int y, int z, BiomeType biome) { - return extent.setBiome(x, y, z, biome); + public boolean setBiome(BlockVector3 position, BiomeType biome) { + //FAWE start - switch to x,y,z + return extent.setBiome(position.getX(), position.getY(), position.getZ(), biome); + //FAWE end } + //FAWE start @Override - public boolean setBiome(BlockVector3 position, BiomeType biome) { - return extent.setBiome(position.getX(), position.getY(), position.getZ(), biome); + public boolean setBiome(int x, int y, int z, BiomeType biome) { + return extent.setBiome(x, y, z, biome); } @Override From 04b4681ecad694bba369ee254d2ac7b10d25b3a6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 22 Dec 2023 17:56:50 +0100 Subject: [PATCH 102/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.0.11 (#2527) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 57aaf1fcf..2ed4c61dd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "16.18.1" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.0.8" +towny = "0.100.0.11" plotsquared = "7.2.1" # Third party From af1230b98eb8dba3fefcdfdc0dca6dc9f171eb46 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 22 Dec 2023 17:57:01 +0100 Subject: [PATCH 103/466] Update dependency io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin to v1.5.11 (#2528) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 8b4b57369..fdb47a435 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -24,7 +24,7 @@ dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.2.1") implementation("com.github.johnrengelman:shadow:8.1.1") - implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.10") + implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.11") } kotlin { From 0681de36c1c72f1a3fb8e045668265a034b40b4d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 22 Dec 2023 17:57:08 +0100 Subject: [PATCH 104/466] Update dependency net.kyori:adventure-platform-bukkit to v4.3.2 (#2529) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2ed4c61dd..79cddd351 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -22,7 +22,7 @@ bstats = "3.0.2" sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.14.0" -adventure-bukkit = "4.3.1" +adventure-bukkit = "4.3.2" checkerqual = "3.42.0" truezip = "6.8.4" auto-value = "1.10.4" From 4faf1ea6ec7d7c3f4705488c26d84b9c663b25fc Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Fri, 22 Dec 2023 18:11:37 +0100 Subject: [PATCH 105/466] Update paperweight --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 34dda434a..48c83a606 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ - the().paperDevBundle("1.20.4-R0.1-20231207.202833-1") + the().paperDevBundle("1.20.4-R0.1-20231221.211952-22") compileOnly(libs.paperlib) } From 129bf013c817c6f089fcb554de4947c50dab66e3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 22 Dec 2023 18:11:53 +0100 Subject: [PATCH 106/466] Update adventure to v4.15.0 (#2530) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 79cddd351..299806b45 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -21,7 +21,7 @@ plotsquared = "7.2.1" bstats = "3.0.2" sparsebitset = "1.3" parallelgzip = "1.0.5" -adventure = "4.14.0" +adventure = "4.15.0" adventure-bukkit = "4.3.2" checkerqual = "3.42.0" truezip = "6.8.4" From 2c0fb224fafc92b2251be048a851823244977070 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 22 Dec 2023 18:12:06 +0100 Subject: [PATCH 107/466] Update dependency net.kyori:adventure-nbt to v4.15.0 (#2531) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index 272d3c84f..c66c394fb 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -183,7 +183,7 @@ tasks.named("shadowJar") { include(dependency("org.lz4:lz4-java:1.8.0")) } relocate("net.kyori", "com.fastasyncworldedit.core.adventure") { - include(dependency("net.kyori:adventure-nbt:4.14.0")) + include(dependency("net.kyori:adventure-nbt:4.15.0")) } relocate("com.zaxxer", "com.fastasyncworldedit.core.math") { include(dependency("com.zaxxer:SparseBitSet:1.3")) From e4a214ec9bcde2fc4af912c17d23b98ebe3e6e14 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Fri, 22 Dec 2023 18:13:54 +0100 Subject: [PATCH 108/466] Release 2.8.4 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 8d8f75c3c..313044b85 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s-%s", rootVersion, buildNumber) +version = String.format("%s", rootVersion) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From a4a11265ec732d6f290a7400e94b3c9924363a3c Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Fri, 22 Dec 2023 18:37:07 +0100 Subject: [PATCH 109/466] Back to snapshot for development --- build.gradle.kts | 4 ++-- .../com/fastasyncworldedit/core/queue/IBatchProcessor.java | 4 ++-- .../main/java/com/fastasyncworldedit/core/queue/IChunk.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 313044b85..ad62a28c1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.8.4") +var rootVersion by extra("2.8.5") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s", rootVersion) +version = String.format("%s-%s", rootVersion, buildNumber) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java index b096b93fe..778f85ce4 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java @@ -157,7 +157,7 @@ public interface IBatchProcessor { * @return false if chunk is empty of NBT * @deprecated tiles are stored in chunk-normalised coordinate space and thus cannot use the same function as entities */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.8.4") default boolean trimNBT(IChunkSet set, Function contains) { Set ents = set.getEntities(); if (!ents.isEmpty()) { @@ -175,7 +175,7 @@ public interface IBatchProcessor { * Utility method to trim entity and blocks with a provided contains function. * * @return false if chunk is empty of NBT - * @since TODO + * @since 2.8.4 */ default boolean trimNBT( IChunkSet set, Function containsEntity, Function containsTile diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunk.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunk.java index 5a03a9987..2586ea24c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunk.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunk.java @@ -38,7 +38,7 @@ public interface IChunk extends Trimable, IChunkGet, IChunkSet { * Return the minimum block coordinate of the chunk * * @return BlockVector3 of minimum block coordinate - * @since TODO + * @since 2.8.4 */ default BlockVector3 getChunkBlockCoord() { return BlockVector3.at(getX() << 4, getMinY(), getZ() << 4); From 7b4b384df6234df9b2c69e83ea8a7892ce1cce6d Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sat, 6 Jan 2024 10:53:53 +0100 Subject: [PATCH 110/466] Update upstream --- worldedit-bukkit/build.gradle.kts | 22 +++-- .../clipboard/io/SchematicLoadException.java | 43 ++++++++++ .../clipboard/io/SpongeSchematicReader.java | 14 +++- .../validation/DataValidatorExtent.java | 32 +++++++- .../WorldEditExceptionConverter.java | 6 ++ .../math/transform/AffineTransform.java | 82 +++++++++++-------- .../src/main/resources/lang/strings.json | 1 + 7 files changed, 149 insertions(+), 51 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicLoadException.java diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index c66c394fb..5a9273371 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -141,20 +141,15 @@ tasks.named("jar") { addJarManifest(WorldEditKind.Plugin, includeClasspath = true) tasks.named("shadowJar") { - dependsOn(project.project(":worldedit-bukkit:adapters").subprojects.map { it.tasks.named("assemble") }) - from(Callable { - adapters.resolve() - .map { f -> - zipTree(f).matching { - exclude("META-INF/") - } - } - }) + configurations.add(adapters) archiveFileName.set("${rootProject.name}-Bukkit-${project.version}.${archiveExtension.getOrElse("jar")}") dependencies { // In tandem with not bundling log4j, we shouldn't relocate base package here. // relocate("org.apache.logging", "com.sk89q.worldedit.log4j") relocate("org.antlr.v4", "com.sk89q.worldedit.antlr4") + + exclude(dependency("$group:$name")) + include(dependency(":worldedit-core")) include(dependency(":worldedit-libs:bukkit")) // Purposefully not included, we assume (even though no API exposes it) that Log4J will be present at runtime @@ -192,6 +187,15 @@ tasks.named("shadowJar") { include(dependency("org.anarres:parallelgzip:1.0.5")) } } + + project.project(":worldedit-bukkit:adapters").subprojects.forEach { + dependencies { + include(dependency("${it.group}:${it.name}")) + } + minimize { + exclude(dependency("${it.group}:${it.name}")) + } + } } tasks.named("assemble").configure { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicLoadException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicLoadException.java new file mode 100644 index 000000000..f94216669 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicLoadException.java @@ -0,0 +1,43 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io; + +import com.sk89q.worldedit.util.formatting.text.Component; + +/** + * Raised when a known exception occurs during schematic load. + */ +public final class SchematicLoadException extends RuntimeException { + + private final Component message; + + public SchematicLoadException(Component message) { + this.message = message; + } + + /** + * Get the message of this exception as a rich text component. + * + * @return The rich message + */ + public Component getRichMessage() { + return this.message; + } +} 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 464ef3e4f..83d8c3007 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 @@ -19,6 +19,7 @@ package com.sk89q.worldedit.extent.clipboard.io; +import com.fastasyncworldedit.core.configuration.Caption; import com.google.common.collect.Maps; import com.sk89q.jnbt.AdventureNBTConverter; import com.sk89q.jnbt.ByteArrayTag; @@ -46,6 +47,7 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; @@ -137,9 +139,8 @@ public class SpongeSchematicReader extends NBTSchematicReader { BlockArrayClipboard clip = readVersion1(schematicTag); return readVersion2(clip, schematicTag); } - throw new IOException("This schematic version is not supported; Version: " + schematicVersion + ", DataVersion: " + dataVersion + "." + - "It's very likely your schematic has an invalid file extension, if the schematic has been created on a version lower than" + - "1.13.2, the extension MUST be `.schematic`, elsewise the schematic can't be read properly."); + throw new SchematicLoadException(Caption.of("worldedit.schematic.load.unsupported-version", + TextComponent.of(schematicVersion))); } @Override @@ -169,6 +170,13 @@ public class SpongeSchematicReader extends NBTSchematicReader { // Check Map schematic = schematicTag.getValue(); + // Be lenient about the specific nesting level of the Schematic tag + // Also allows checking the version from newer versions of the specification + if (schematic.size() == 1 && schematic.containsKey("Schematic")) { + schematicTag = requireTag(schematic, "Schematic", CompoundTag.class); + schematic = schematicTag.getValue(); + } + schematicVersion = requireTag(schematic, "Version", IntTag.class).getValue(); return schematicTag; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java index 1b806c7d8..bc498711b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java @@ -24,6 +24,7 @@ import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.Extent; 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; import com.sk89q.worldedit.world.block.BlockType; @@ -34,7 +35,8 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class DataValidatorExtent extends AbstractDelegateExtent { - private final World world; + private final int minY; + private final int maxY; /** * Create a new instance. @@ -43,16 +45,27 @@ public class DataValidatorExtent extends AbstractDelegateExtent { * @param world the world */ public DataValidatorExtent(Extent extent, World world) { + this(extent, checkNotNull(world).getMinY(), world.getMaxY()); + } + + /** + * Create a new instance. + * + * @param extent The extent + * @param minY The minimum Y height to allow (inclusive) + * @param maxY The maximum Y height to allow (inclusive) + */ + public DataValidatorExtent(Extent extent, int minY, int maxY) { super(extent); - checkNotNull(world); - this.world = world; + this.minY = minY; + this.maxY = maxY; } @Override public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { final int y = location.getBlockY(); final BlockType type = block.getBlockType(); - if (y < world.getMinY() || y > world.getMaxY()) { + if (y < minY || y > maxY) { return false; } @@ -64,4 +77,15 @@ public class DataValidatorExtent extends AbstractDelegateExtent { return super.setBlock(location, block); } + @Override + public boolean setBiome(BlockVector3 location, BiomeType biome) { + final int y = location.getBlockY(); + + if (y < minY || y > maxY) { + return false; + } + + return super.setBiome(location, biome); + } + } 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 3f5bfafb5..a0c5eb328 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 @@ -36,6 +36,7 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.InsufficientArgumentsException; import com.sk89q.worldedit.command.tool.InvalidToolBindException; +import com.sk89q.worldedit.extent.clipboard.io.SchematicLoadException; import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.util.formatting.text.Component; @@ -187,6 +188,11 @@ public class WorldEditExceptionConverter extends ExceptionConverterHelper { throw newCommandException(Caption.of("worldedit.error.file-aborted"), e); } + @ExceptionMatch + public void convert(SchematicLoadException e) throws CommandException { + throw newCommandException(e.getRichMessage(), e); + } + @ExceptionMatch public void convert(WorldEditException e) throws CommandException { throw newCommandException(e.getRichMessage(), e); 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 c06e0968e..02ee75d44 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 @@ -195,6 +195,33 @@ public class AffineTransform implements Transform, Serializable { // =================================================================== // general methods + /** + * Returns the affine transform created by applying first the affine + * transform given by the parameters, then this affine transform. + * + * @return the composition this * that + */ + public AffineTransform concatenate(double o00, double o01, double o02, double o03, + double o10, double o11, double o12, double o13, + double o20, double o21, double o22, double o23) { + double n00 = m00 * o00 + m01 * o10 + m02 * o20; + double n01 = m00 * o01 + m01 * o11 + m02 * o21; + double n02 = m00 * o02 + m01 * o12 + m02 * o22; + double n03 = m00 * o03 + m01 * o13 + m02 * o23 + m03; + double n10 = m10 * o00 + m11 * o10 + m12 * o20; + double n11 = m10 * o01 + m11 * o11 + m12 * o21; + double n12 = m10 * o02 + m11 * o12 + m12 * o22; + double n13 = m10 * o03 + m11 * o13 + m12 * o23 + m13; + double n20 = m20 * o00 + m21 * o10 + m22 * o20; + double n21 = m20 * o01 + m21 * o11 + m22 * o21; + double n22 = m20 * o02 + m21 * o12 + m22 * o22; + double n23 = m20 * o03 + m21 * o13 + m22 * o23 + m23; + return new AffineTransform( + n00, n01, n02, n03, + n10, n11, n12, n13, + n20, n21, n22, n23); + } + /** * Returns the affine transform created by applying first the affine * transform given by {@code that}, then this affine transform. @@ -203,22 +230,10 @@ public class AffineTransform implements Transform, Serializable { * @return the composition this * that */ public AffineTransform concatenate(AffineTransform that) { - double n00 = m00 * that.m00 + m01 * that.m10 + m02 * that.m20; - double n01 = m00 * that.m01 + m01 * that.m11 + m02 * that.m21; - double n02 = m00 * that.m02 + m01 * that.m12 + m02 * that.m22; - double n03 = m00 * that.m03 + m01 * that.m13 + m02 * that.m23 + m03; - double n10 = m10 * that.m00 + m11 * that.m10 + m12 * that.m20; - double n11 = m10 * that.m01 + m11 * that.m11 + m12 * that.m21; - double n12 = m10 * that.m02 + m11 * that.m12 + m12 * that.m22; - double n13 = m10 * that.m03 + m11 * that.m13 + m12 * that.m23 + m13; - double n20 = m20 * that.m00 + m21 * that.m10 + m22 * that.m20; - double n21 = m20 * that.m01 + m21 * that.m11 + m22 * that.m21; - double n22 = m20 * that.m02 + m21 * that.m12 + m22 * that.m22; - double n23 = m20 * that.m03 + m21 * that.m13 + m22 * that.m23 + m23; - return new AffineTransform( - n00, n01, n02, n03, - n10, n11, n12, n13, - n20, n21, n22, n23 + return concatenate( + that.m00, that.m01, that.m02, that.m03, + that.m10, that.m11, that.m12, that.m13, + that.m20, that.m21, that.m22, that.m23 ); } @@ -258,40 +273,37 @@ public class AffineTransform implements Transform, Serializable { } public AffineTransform translate(double x, double y, double z) { - return concatenate(new AffineTransform(1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z)); + return concatenate(1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z); } public AffineTransform rotateX(double theta) { double cot = MathUtils.dCos(theta); double sit = MathUtils.dSin(theta); return concatenate( - new AffineTransform( - 1, 0, 0, 0, - 0, cot, -sit, 0, - 0, sit, cot, 0 - )); + 1, 0, 0, 0, + 0, cot, -sit, 0, + 0, sit, cot, 0 + ); } public AffineTransform rotateY(double theta) { double cot = MathUtils.dCos(theta); double sit = MathUtils.dSin(theta); return concatenate( - new AffineTransform( - cot, 0, sit, 0, - 0, 1, 0, 0, - -sit, 0, cot, 0 - )); + cot, 0, sit, 0, + 0, 1, 0, 0, + -sit, 0, cot, 0 + ); } public AffineTransform rotateZ(double theta) { double cot = MathUtils.dCos(theta); double sit = MathUtils.dSin(theta); return concatenate( - new AffineTransform( - cot, -sit, 0, 0, - sit, cot, 0, 0, - 0, 0, 1, 0 - )); + cot, -sit, 0, 0, + sit, cot, 0, 0, + 0, 0, 1, 0 + ); } public AffineTransform scale(double s) { @@ -299,7 +311,7 @@ public class AffineTransform implements Transform, Serializable { } public AffineTransform scale(double sx, double sy, double sz) { - return concatenate(new AffineTransform(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0)); + return concatenate(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0); } public AffineTransform scale(Vector3 vec) { @@ -352,9 +364,9 @@ public class AffineTransform implements Transform, Serializable { //FAWE start - check other identity if (other instanceof Identity || other.isIdentity()) { return this; - } else if (other instanceof AffineTransform) { + } else if (other instanceof AffineTransform otherTransform) { //FAWE end - return concatenate((AffineTransform) other); + return concatenate(otherTransform); } else { return new CombinedTransform(this, other); } diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index 3d1295ab0..208de9027 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -354,6 +354,7 @@ "worldedit.schematic.unknown-format": "Unknown schematic format: {0}.", "worldedit.schematic.load.does-not-exist": "Schematic {0} does not exist!", "worldedit.schematic.load.loading": "(Please wait... loading schematic.)", + "worldedit.schematic.load.unsupported-version": "This schematic is not supported. Version: {0}.", "worldedit.schematic.save.already-exists": "That schematic already exists. Use the -f flag to overwrite it.", "worldedit.schematic.save.failed-directory": "Could not create folder for schematics!", "worldedit.schematic.save.saving": "(Please wait... saving schematic.)", From b3905c2a6dc8a0a6071c96db8436a88702eeb794 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 7 Jan 2024 20:53:32 +0100 Subject: [PATCH 111/466] Update Paperweight Signed-off-by: Alexander Brandes --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 48c83a606..88a2a0fcf 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ - the().paperDevBundle("1.20.4-R0.1-20231221.211952-22") + the().paperDevBundle("1.20.4-R0.1-20240106.182028-62") compileOnly(libs.paperlib) } From a7c5f66a4595b59fc823b8512f0494111b41251c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 20 Jan 2024 00:32:45 +0100 Subject: [PATCH 112/466] Update plotsquared to v7.3.1 (#2536) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 299806b45..71a034d45 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ griefprevention = "16.18.1" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" towny = "0.100.0.11" -plotsquared = "7.2.1" +plotsquared = "7.3.1" # Third party bstats = "3.0.2" From e81507113479fda17fc91df4f9d6304a430c3a1d Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 21 Jan 2024 12:42:24 +0100 Subject: [PATCH 113/466] fix: fix plot swap (#2360) - deprecate and note for internal use only Clipboard#create as it's funky - fixes #2076 --- .../FaweDelegateRegionManager.java | 27 ++++++++++--------- .../worldedit/extent/clipboard/Clipboard.java | 6 +++++ 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateRegionManager.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateRegionManager.java index 65f8863f8..c111ff630 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateRegionManager.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateRegionManager.java @@ -16,6 +16,7 @@ import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import com.sk89q.worldedit.function.FlatRegionFunction; @@ -217,7 +218,6 @@ public class FaweDelegateRegionManager { ) { TaskManager.taskManager().async(() -> { synchronized (FaweDelegateRegionManager.class) { - //todo because of the following code this should probably be in the Bukkit module World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName())); World pos3World = BukkitAdapter.adapt(getWorld(swapPos.getWorldName())); EditSession sessionA = WorldEdit.getInstance().newEditSessionBuilder().world(pos1World) @@ -236,14 +236,16 @@ public class FaweDelegateRegionManager { CuboidRegion regionB = new CuboidRegion( pos3World, swapPos.getBlockVector3(), - swapPos.getBlockVector3().add(pos2.getBlockVector3()).subtract(pos1.getBlockVector3()) + swapPos.getBlockVector3().add(pos2.getBlockVector3().subtract(pos1.getBlockVector3())).withY(pos2.getY()) ); - Clipboard clipA = Clipboard.create(regionA, UUID.randomUUID()); - Clipboard clipB = Clipboard.create(regionB, UUID.randomUUID()); + Clipboard clipA = new BlockArrayClipboard(regionA, UUID.randomUUID()); + Clipboard clipB = new BlockArrayClipboard(regionB, UUID.randomUUID()); ForwardExtentCopy copyA = new ForwardExtentCopy(sessionA, regionA, clipA, clipA.getMinimumPoint()); ForwardExtentCopy copyB = new ForwardExtentCopy(sessionB, regionB, clipB, clipB.getMinimumPoint()); copyA.setCopyingBiomes(true); copyB.setCopyingBiomes(true); + copyA.setCopyingEntities(true); + copyB.setCopyingEntities(true); try { Operations.completeLegacy(copyA); Operations.completeLegacy(copyB); @@ -257,17 +259,16 @@ public class FaweDelegateRegionManager { sessionA.close(); sessionB.close(); } - FaweAPI.fixLighting(pos1World, new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3()), null, + FaweAPI.fixLighting( + pos1World, + regionA, + null, RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.settings().LIGHTING.MODE) ); - FaweAPI.fixLighting(pos1World, new CuboidRegion( - swapPos.getBlockVector3(), - BlockVector3.at( - swapPos.getX() + pos2.getX() - pos1.getX(), - 0, - swapPos.getZ() + pos2.getZ() - pos1.getZ() - ) - ), null, + FaweAPI.fixLighting( + pos1World, + regionB, + null, RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.settings().LIGHTING.MODE) ); if (whenDone != null) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java index 15d6365e7..76e866c33 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java @@ -73,7 +73,10 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl /** * Creates a new {@link ReadOnlyClipboard}. + * + * @deprecated Internal use only. Use {@link BlockArrayClipboard#BlockArrayClipboard(Region)} */ + @Deprecated static Clipboard create(Region region) { checkNotNull(region); checkNotNull( @@ -95,7 +98,10 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl * - {@link DiskOptimizedClipboard} * - {@link CPUOptimizedClipboard} * - {@link MemoryOptimizedClipboard} + * + * @deprecated Internal use only. Use {@link BlockArrayClipboard#BlockArrayClipboard(Region, UUID)} */ + @Deprecated static Clipboard create(Region region, UUID uuid) { if (Settings.settings().CLIPBOARD.USE_DISK) { return new DiskOptimizedClipboard(region, uuid); From ea6bbecc32ccd25f2fe1b03decb695d4afe5fbcb Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Mon, 22 Jan 2024 19:14:10 +0100 Subject: [PATCH 114/466] Track paperweight-userdev versions with renovate (#2548) * fix: editorconfig file selectors * chore/ci: add renovate checks for paperweight-userdev --- .editorconfig | 20 ++++---- .github/renovate.json | 50 +++++++++++++++---- .../adapters/adapter-1_17_1/build.gradle.kts | 1 + .../adapters/adapter-1_18_2/build.gradle.kts | 2 +- .../adapters/adapter-1_19_4/build.gradle.kts | 1 + .../adapters/adapter-1_20/build.gradle.kts | 2 +- .../adapters/adapter-1_20_2/build.gradle.kts | 2 +- .../adapters/adapter-1_20_4/build.gradle.kts | 2 +- 8 files changed, 56 insertions(+), 24 deletions(-) diff --git a/.editorconfig b/.editorconfig index e43c0e094..c60879fb3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -342,7 +342,7 @@ ij_editorconfig_space_before_colon = false ij_editorconfig_space_before_comma = false ij_editorconfig_spaces_around_assignment_operators = true -[{*.ant, *.fxml, *.jhm, *.jnlp, *.jrxml, *.pom, *.rng, *.tld, *.wsdl, *.xml, *.xsd, *.xsl, *.xslt, *.xul}] +[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.pom,*.rng,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul}] ij_xml_align_attributes = true ij_xml_align_text = false ij_xml_attribute_wrap = normal @@ -360,7 +360,7 @@ ij_xml_space_around_equals_in_attribute = false ij_xml_space_inside_empty_tag = false ij_xml_text_wrap = normal -[{*.ats, *.ts}] +[{*.ats,*.ts}] ij_continuation_indent_size = 4 ij_typescript_align_imports = false ij_typescript_align_multiline_array_initializer_expression = false @@ -528,7 +528,7 @@ ij_typescript_while_brace_force = never ij_typescript_while_on_new_line = false ij_typescript_wrap_comments = false -[{*.bash, *.sh, *.zsh}] +[{*.bash,*.sh,*.zsh}] indent_size = 2 tab_width = 2 ij_shell_binary_ops_start_line = false @@ -537,7 +537,7 @@ ij_shell_minify_program = false ij_shell_redirect_followed_by_space = false ij_shell_switch_cases_indented = false -[{*.cjs, *.js}] +[{*.cjs,*.js}] ij_continuation_indent_size = 4 ij_javascript_align_imports = false ij_javascript_align_multiline_array_initializer_expression = false @@ -702,10 +702,10 @@ ij_javascript_while_brace_force = never ij_javascript_while_on_new_line = false ij_javascript_wrap_comments = false -[{*.ft, *.vm, *.vsl}] +[{*.ft,*.vm,*.vsl}] ij_vtl_keep_indents_on_empty_lines = false -[{*.gant, *.gradle, *.groovy, *.gy}] +[{*.gant,*.gradle,*.groovy,*.gy}] ij_groovy_align_group_field_declarations = false ij_groovy_align_multiline_array_initializer_expression = false ij_groovy_align_multiline_assignment = false @@ -884,7 +884,7 @@ ij_groovy_while_brace_force = never ij_groovy_while_on_new_line = false ij_groovy_wrap_long_lines = false -[{*.gradle.kts, *.kt, *.kts, *.main.kts}] +[{*.gradle.kts,*.kt,*.kts,*.main.kts}] ij_kotlin_align_in_columns_case_branch = false ij_kotlin_align_multiline_binary_operation = false ij_kotlin_align_multiline_extends_list = false @@ -963,7 +963,7 @@ ij_kotlin_wrap_elvis_expressions = 1 ij_kotlin_wrap_expression_body_functions = 0 ij_kotlin_wrap_first_method_in_call_chain = false -[{*.har, *.jsb2, *.jsb3, *.json, .babelrc, .eslintrc, .stylelintrc, bowerrc, jest.config, mcmod.info}] +[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,jest.config,mcmod.info}] indent_size = 2 ij_json_keep_blank_lines_in_code = 0 ij_json_keep_indents_on_empty_lines = false @@ -976,7 +976,7 @@ ij_json_spaces_within_braces = false ij_json_spaces_within_brackets = false ij_json_wrap_long_lines = false -[{*.htm, *.html, *.sht, *.shtm, *.shtml}] +[{*.htm,*.html,*.sht,*.shtm,*.shtml}] ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3 ij_html_align_attributes = true ij_html_align_text = false @@ -1004,7 +1004,7 @@ ij_html_space_inside_empty_tag = false ij_html_text_wrap = normal ij_html_uniform_ident = false -[{*.yaml, *.yml}] +[{*.yaml,*.yml}] indent_size = 2 ij_yaml_keep_indents_on_empty_lines = false ij_yaml_keep_line_breaks = true diff --git a/.github/renovate.json b/.github/renovate.json index d0e59d791..740d991fb 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,18 +1,18 @@ { - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:base", + "$schema" : "https://docs.renovatebot.com/renovate-schema.json", + "extends" : [ + "config:recommended", ":semanticCommitsDisabled" ], - "automerge": true, - "ignoreDeps": [ - "guava", + "automerge" : true, + "ignoreDeps" : [ + "guava", "com.google.guava:guava", "rhino-runtime", "org.antlr", "antlr4-runtime", "fastutil", - "it.unimi.dsi:fastutil", + "it.unimi.dsi:fastutil", "auto-value-annotations", "auto-value", "com.google.code.gson:gson", @@ -29,7 +29,37 @@ "org.spongepowered:spongeapi", "org.yaml:snakeyaml" ], - "labels": ["Renovate"], - "rebaseWhen": "conflicted", - "schedule": ["on the first day of the month"] + "labels" : [ + "Renovate" + ], + "rebaseWhen" : "conflicted", + "schedule" : [ + "on the first day of the month" + ], + "customManagers" : [ + { + "customType" : "regex", + "datasourceTemplate" : "custom.paperweight-userdev", + "fileMatch" : "^worldedit-bukkit\\/adapters\\/adapter-\\d+_\\d+(_\\d+)?\\/build\\.gradle\\.kts$", + "matchStrings" : [ + "url=(?.*)\\s", + "paperDevBundle\\(\"(?.*?)\"\\)\\s" + ], + "matchStringsStrategy": "combination", + "depNameTemplate" : "paperweight-userdev", + "extractVersionTemplate" : "(?\\d+\\.\\d+\\.?\\d*-R0\\.1-\\d+\\.\\d+-\\d+)" + } + ], + "customDatasources" : { + "paperweight-userdev": { + "defaultRegistryUrlTemplate": "", + "format": "html" + } + }, + "packageRules" : [ + { + "matchDatasources" : ["custom.paperweight-userdev"], + "versioning": "regex:^(?\\d+)\\.(?\\d+)\\.(?\\d+)?-R0\\.1-\\d+\\d+\\.\\d+-(?\\d+)$" + } + ] } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_17_1/build.gradle.kts index 24c121c3f..9eb68ea36 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_17_1/build.gradle.kts @@ -21,6 +21,7 @@ configurations.all { dependencies { + // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.17.1-R0.1-SNAPSHOT the().paperDevBundle("1.17.1-R0.1-20220414.034903-210") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_18_2/build.gradle.kts index f7f40ce66..3713af207 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_18_2/build.gradle.kts @@ -11,7 +11,7 @@ repositories { } dependencies { - // https://papermc.io/repo/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ + // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.18.2-R0.1-SNAPSHOT the().paperDevBundle("1.18.2-R0.1-20220920.010157-167") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_19_4/build.gradle.kts index df27ae5d6..e53d2497e 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_19_4/build.gradle.kts @@ -11,6 +11,7 @@ repositories { } dependencies { + // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.19.4-R0.1-SNAPSHOT the().paperDevBundle("1.19.4-R0.1-20230608.201059-104") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts index 227eee362..51438592a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts @@ -11,7 +11,7 @@ repositories { } dependencies { - // https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ + // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.1-R0.1-SNAPSHOT the().paperDevBundle("1.20.1-R0.1-20230921.165944-178") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts index 3b08adfe8..995446059 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts @@ -11,7 +11,7 @@ repositories { } dependencies { - // https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ + // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.2-R0.1-SNAPSHOT the().paperDevBundle("1.20.2-R0.1-20231203.034718-121") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 88a2a0fcf..02f5a3c53 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -11,7 +11,7 @@ repositories { } dependencies { - // https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ + // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT the().paperDevBundle("1.20.4-R0.1-20240106.182028-62") compileOnly(libs.paperlib) } From a99dd2d387322cc57d1821376a8d4c96ab6f63c7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 Jan 2024 21:01:11 +0100 Subject: [PATCH 115/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.1.5 (#2550) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 71a034d45..86527e5b8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "16.18.1" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.0.11" +towny = "0.100.1.5" plotsquared = "7.3.1" # Third party From 325309e39673e06de12fa5d96ec4d665bf372d43 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 Jan 2024 21:01:24 +0100 Subject: [PATCH 116/466] Update dependency com.github.TechFortress:GriefPrevention to v17 (#2552) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 86527e5b8..c8f7b7c9e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ snakeyaml = "2.0" dummypermscompat = "1.10" worldguard-bukkit = "7.0.9" mapmanager = "1.8.0-SNAPSHOT" -griefprevention = "16.18.1" +griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" towny = "0.100.1.5" From b919633a87d47eecab154e4980b86d00f4fc1294 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 Jan 2024 21:01:30 +0100 Subject: [PATCH 117/466] Update dependency org.mockito:mockito-core to v5.9.0 (#2551) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- worldedit-sponge/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c8f7b7c9e..9d255510e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -46,7 +46,7 @@ text = "3.0.4" piston = "0.5.7" # Tests -mockito = "5.8.0" +mockito = "5.9.0" # Gradle plugins pluginyml = "0.6.0" diff --git a/worldedit-sponge/build.gradle.kts b/worldedit-sponge/build.gradle.kts index 8d3ba1539..272ea46ec 100644 --- a/worldedit-sponge/build.gradle.kts +++ b/worldedit-sponge/build.gradle.kts @@ -28,7 +28,7 @@ dependencies { }) api("org.apache.logging.log4j:log4j-api") api("org.bstats:bstats-sponge:1.7") - testImplementation("org.mockito:mockito-core:5.8.0") + testImplementation("org.mockito:mockito-core:5.9.0") } <<<<<<< HEAD From 763a497cdcf63bc73983529835f21497d111d259 Mon Sep 17 00:00:00 2001 From: Zeranny Date: Sun, 28 Jan 2024 12:10:48 +0000 Subject: [PATCH 118/466] Fix out of bounds error for erode and pull brushes (#2554) - Fixes #2380 --- .../core/command/tool/brush/ErodeBrush.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ErodeBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ErodeBrush.java index 13490dc2f..21879751c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ErodeBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ErodeBrush.java @@ -67,11 +67,11 @@ public class ErodeBrush implements Brush { final int by = target.getBlockY(); final int bz = target.getBlockZ(); - for (int x = -brushSize, relx = 0; x <= brushSize; x++, relx++) { + for (int x = -brushSize, relx = 0; x <= brushSize && relx < buffer1.getWidth(); x++, relx++) { int x0 = x + bx; - for (int y = -brushSize, rely = 0; y <= brushSize; y++, rely++) { + for (int y = -brushSize, rely = 0; y <= brushSize && rely < buffer1.getHeight(); y++, rely++) { int y0 = y + by; - for (int z = -brushSize, relz = 0; z <= brushSize; z++, relz++) { + for (int z = -brushSize, relz = 0; z <= brushSize && relz < buffer1.getLength(); z++, relz++) { int z0 = z + bz; BlockState state = es.getBlock(x0, y0, z0); buffer1.setBlock(relx, rely, relz, state); @@ -115,11 +115,11 @@ public class ErodeBrush implements Brush { Clipboard current, Clipboard target ) { int[] frequency = null; - for (int x = -brushSize, relx = 0; x <= brushSize; x++, relx++) { + for (int x = -brushSize, relx = 0; x <= brushSize && relx < target.getWidth(); x++, relx++) { int x2 = x * x; - for (int z = -brushSize, relz = 0; z <= brushSize; z++, relz++) { + for (int z = -brushSize, relz = 0; z <= brushSize && relz < target.getLength(); z++, relz++) { int x2y2 = x2 + z * z; - for (int y = -brushSize, rely = 0; y <= brushSize; y++, rely++) { + for (int y = -brushSize, rely = 0; y <= brushSize && rely < target.getHeight(); y++, rely++) { int cube = x2y2 + y * y; target.setBlock(relx, rely, relz, current.getBlock(relx, rely, relz)); if (cube >= brushSizeSquared) { @@ -166,11 +166,11 @@ public class ErodeBrush implements Brush { Clipboard current, Clipboard target ) { int[] frequency = null; - for (int x = -brushSize, relx = 0; x <= brushSize; x++, relx++) { + for (int x = -brushSize, relx = 0; x <= brushSize && relx < target.getWidth(); x++, relx++) { int x2 = x * x; - for (int z = -brushSize, relz = 0; z <= brushSize; z++, relz++) { + for (int z = -brushSize, relz = 0; z <= brushSize && relz < target.getLength(); z++, relz++) { int x2y2 = x2 + z * z; - for (int y = -brushSize, rely = 0; y <= brushSize; y++, rely++) { + for (int y = -brushSize, rely = 0; y <= brushSize && rely < target.getHeight(); y++, rely++) { int cube = x2y2 + y * y; target.setBlock(relx, rely, relz, current.getBlock(relx, rely, relz)); if (cube >= brushSizeSquared) { From 9ffe76dce3fe5bb46fe02897b1fb3721a6eab3eb Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sun, 28 Jan 2024 13:32:25 +0100 Subject: [PATCH 119/466] fix: add missing methods top TestOfflinePermissible --- .../java/com/sk89q/wepif/TestOfflinePermissible.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java b/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java index 052c772d5..507da7e01 100644 --- a/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java +++ b/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java @@ -245,6 +245,11 @@ public class TestOfflinePermissible implements OfflinePlayer, Permissible { throw new UnsupportedOperationException("Not supported yet."); } + @Override + public @Nullable Location getRespawnLocation() { + return null; + } + @Override public void incrementStatistic(@Nonnull Statistic statistic) throws IllegalArgumentException { @@ -365,4 +370,9 @@ public class TestOfflinePermissible implements OfflinePlayer, Permissible { return null; } + @Override + public @Nullable Location getLocation() { + return null; + } + } From 033b8e35d235205c6f72f09156b0b4a3d393a4da Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 2 Feb 2024 18:06:57 +0100 Subject: [PATCH 120/466] fix: always set createCopy status on chunk get as chunks are cached (#2567) - fixes #2539 --- .../adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java | 1 + .../bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java | 1 + .../bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java | 1 + .../bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java | 1 + .../bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java | 1 + .../bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java | 1 + .../core/queue/implementation/chunk/ChunkHolder.java | 2 +- 7 files changed, 7 insertions(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java index a93437c1a..214a39bc6 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java @@ -148,6 +148,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); } this.createCopy = createCopy; + // Increment regardless of whether copy will be created or not to return null from getCopy() return ++this.copyKey; } diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java index 81580910c..7291c0f69 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java @@ -153,6 +153,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); } this.createCopy = createCopy; + // Increment regardless of whether copy will be created or not to return null from getCopy() return ++this.copyKey; } diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java index 60695c1e8..63bdb5997 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java @@ -156,6 +156,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); } this.createCopy = createCopy; + // Increment regardless of whether copy will be created or not to return null from getCopy() return ++this.copyKey; } diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java index 67bcd6902..5f74d1073 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java @@ -156,6 +156,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); } this.createCopy = createCopy; + // Increment regardless of whether copy will be created or not to return null from getCopy() return ++this.copyKey; } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java index d51d31500..1531358fb 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java @@ -135,6 +135,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); } this.createCopy = createCopy; + // Increment regardless of whether copy will be created or not to return null from getCopy() return ++this.copyKey; } diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java index 8139adc87..42333f9e5 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java @@ -135,6 +135,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); } this.createCopy = createCopy; + // Increment regardless of whether copy will be created or not to return null from getCopy() return ++this.copyKey; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java index e4a18ef69..9458aa1b0 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java @@ -1031,10 +1031,10 @@ public class ChunkHolder> implements IQueueChunk { try { get.lockCall(); boolean postProcess = !(getExtent().getPostProcessor() instanceof EmptyBatchProcessor); + final int copyKey = get.setCreateCopy(postProcess); final IChunkSet iChunkSet = getExtent().processSet(this, get, set); Runnable finalizer; if (postProcess) { - int copyKey = get.setCreateCopy(true); finalizer = () -> { getExtent().postProcess(this, get.getCopy(copyKey), iChunkSet); finalize.run(); From a502287906da63cc689d53eeba855ef7df9efea9 Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 2 Feb 2024 18:07:13 +0100 Subject: [PATCH 121/466] refactor: minor adjustments to error handling (ignoring) and blocking queue (#2566) --- .../fastasyncworldedit/core/FaweCache.java | 36 ++++++++++++++++--- .../queue/implementation/QueueHandler.java | 3 +- .../SingleThreadQueueExtent.java | 1 + .../implementation/chunk/ChunkHolder.java | 3 +- 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java index 0655e4214..f5cc88284 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java @@ -612,12 +612,38 @@ public enum FaweCache implements Trimable { /* Thread stuff */ + + /** + * Create a new blocking executor with default name and FaweCache logger + * + * @return new blocking executor + */ public ThreadPoolExecutor newBlockingExecutor() { + return newBlockingExecutor("FAWE Blocking Executor - %d"); + } + + /** + * Create a new blocking executor with specified name and FaweCache logger + * + * @return new blocking executor + * @since TODO + */ + public ThreadPoolExecutor newBlockingExecutor(String name) { + return newBlockingExecutor(name, LOGGER); + } + + /** + * Create a new blocking executor with specified name and logger + * + * @return new blocking executor + * @since TODO + */ + public ThreadPoolExecutor newBlockingExecutor(String name, Logger logger) { int nThreads = Settings.settings().QUEUE.PARALLEL_THREADS; ArrayBlockingQueue queue = new ArrayBlockingQueue<>(nThreads, true); return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, queue, - new ThreadFactoryBuilder().setNameFormat("FAWE Blocking Executor - %d").build(), + new ThreadFactoryBuilder().setNameFormat(name).build(), new ThreadPoolExecutor.CallerRunsPolicy() ) { @@ -652,10 +678,10 @@ public enum FaweCache implements Trimable { int hash = throwable.getMessage() != null ? throwable.getMessage().hashCode() : 0; if (hash != lastException) { lastException = hash; - LOGGER.catching(throwable); + logger.catching(throwable); count = 0; } else if (count < Settings.settings().QUEUE.PARALLEL_THREADS) { - LOGGER.warn(throwable.getMessage()); + logger.warn(throwable.getMessage()); count++; } } @@ -665,10 +691,10 @@ public enum FaweCache implements Trimable { private void handleFaweException(FaweException e) { FaweException.Type type = e.getType(); if (e.getType() == FaweException.Type.OTHER) { - LOGGER.catching(e); + logger.catching(e); } else if (!faweExceptionReasonsUsed[type.ordinal()]) { faweExceptionReasonsUsed[type.ordinal()] = true; - LOGGER.warn("FaweException: " + e.getMessage()); + logger.warn("FaweException: " + e.getMessage()); } } }; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/QueueHandler.java index 014b94fce..956c33fb2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/QueueHandler.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/QueueHandler.java @@ -68,7 +68,8 @@ public abstract class QueueHandler implements Trimable, Runnable { * Main "work-horse" queue for FAWE. Handles chunk submission (and chunk submission alone). Blocking in order to forcibly * prevent overworking/over-submission of chunk process tasks. */ - private final ThreadPoolExecutor blockingExecutor = FaweCache.INSTANCE.newBlockingExecutor(); + private final ThreadPoolExecutor blockingExecutor = FaweCache.INSTANCE.newBlockingExecutor( + "FAWE QueueHandler Blocking Executor - %d"); /** * Queue for tasks to be completed on the main thread. These take priority of tasks submitted to syncWhenFree queue */ diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java index 34dd5191e..132229d1d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java @@ -158,6 +158,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen this.setProcessor(EmptyBatchProcessor.getInstance()); this.setPostProcessor(EmptyBatchProcessor.getInstance()); this.world = null; + this.faweExceptionReasonsUsed = new boolean[FaweException.Type.values().length]; } /** diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java index 9458aa1b0..6103a1649 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java @@ -12,6 +12,7 @@ import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.fastasyncworldedit.core.queue.Pool; +import com.fastasyncworldedit.core.util.MemUtil; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; @@ -959,7 +960,7 @@ public class ChunkHolder> implements IQueueChunk { public final IChunkGet getOrCreateGet() { if (chunkExisting == null) { chunkExisting = newWrappedGet(); - chunkExisting.trim(false); + chunkExisting.trim(MemUtil.isMemoryLimited()); } return chunkExisting; } From d1e1d5105e04dcce486aed1ae18e6866ae0881e3 Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 5 Feb 2024 22:44:45 +0100 Subject: [PATCH 122/466] fix: invalidate cached allowed regions if WG region deleted (#2572) --- .../bukkit/regions/WorldGuardFeature.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java index ade2d8258..1043d9a3e 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java @@ -163,13 +163,22 @@ public class WorldGuardFeature extends BukkitMaskManager implements Listener { final Location location = player.getLocation(); final Set regions = this.getRegions(localplayer, location, isWhitelist); if (!regions.isEmpty()) { + RegionManager manager = WorldGuard + .getInstance() + .getPlatform() + .getRegionContainer() + .get(BukkitAdapter.adapt(location.getWorld())); + if (manager == null) { + return null; + } Set result = new HashSet<>(); for (ProtectedRegion myRegion : regions) { if (myRegion.getId().equals("__global__")) { return new FaweMask(RegionWrapper.GLOBAL()) { @Override public boolean isValid(com.sk89q.worldedit.entity.Player player, MaskType type) { - return isAllowed(worldguard.wrapPlayer(BukkitAdapter.adapt(player)), myRegion); + return manager.hasRegion(myRegion.getId()) + && isAllowed(worldguard.wrapPlayer(BukkitAdapter.adapt(player)), myRegion); } }; } else { @@ -185,7 +194,7 @@ public class WorldGuardFeature extends BukkitMaskManager implements Listener { public boolean isValid(com.sk89q.worldedit.entity.Player player, MaskType type) { final LocalPlayer localplayer = worldguard.wrapPlayer(BukkitAdapter.adapt(player)); for (ProtectedRegion myRegion : regions) { - if (!isAllowed(localplayer, myRegion)) { + if (!manager.hasRegion(myRegion.getId()) || !isAllowed(localplayer, myRegion)) { return false; } } From 36ce7afcfffa26eeaf88026a372b952f82ab68b0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 5 Feb 2024 22:45:15 +0100 Subject: [PATCH 123/466] Update gradle/wrapper-validation-action action to v2 (#2565) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build-pr.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/upload-release-assets.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index 394cb9f56..de239164e 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -11,7 +11,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/wrapper-validation-action@v2 - name: Setup Java uses: actions/setup-java@v4 with: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 571658fb4..675f0cc1c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/wrapper-validation-action@v2 - name: Setup Java uses: actions/setup-java@v4 with: diff --git a/.github/workflows/upload-release-assets.yml b/.github/workflows/upload-release-assets.yml index 7315f1d6c..a621e9d13 100644 --- a/.github/workflows/upload-release-assets.yml +++ b/.github/workflows/upload-release-assets.yml @@ -9,7 +9,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/wrapper-validation-action@v2 - name: Setup Java uses: actions/setup-java@v4 with: From 9beda23f4a66e2680f750c7e27b8e90b573ce01a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 5 Feb 2024 22:45:23 +0100 Subject: [PATCH 124/466] Update dependency org.mockito:mockito-core to v5.10.0 (#2564) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- worldedit-sponge/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9d255510e..5e715d3e3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -46,7 +46,7 @@ text = "3.0.4" piston = "0.5.7" # Tests -mockito = "5.9.0" +mockito = "5.10.0" # Gradle plugins pluginyml = "0.6.0" diff --git a/worldedit-sponge/build.gradle.kts b/worldedit-sponge/build.gradle.kts index 272ea46ec..c37fe591e 100644 --- a/worldedit-sponge/build.gradle.kts +++ b/worldedit-sponge/build.gradle.kts @@ -28,7 +28,7 @@ dependencies { }) api("org.apache.logging.log4j:log4j-api") api("org.bstats:bstats-sponge:1.7") - testImplementation("org.mockito:mockito-core:5.9.0") + testImplementation("org.mockito:mockito-core:5.10.0") } <<<<<<< HEAD From f6c82eaa8234a554b541e6458fa8de4bc8772553 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 5 Feb 2024 22:45:32 +0100 Subject: [PATCH 125/466] Update plotsquared to v7.3.2 (#2563) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5e715d3e3..bd29cd455 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" towny = "0.100.1.5" -plotsquared = "7.3.1" +plotsquared = "7.3.2" # Third party bstats = "3.0.2" From 40f0c7ca9f8fe497ebb81834469f28f02c6c84ee Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 15:12:08 +0100 Subject: [PATCH 126/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.1.10 (#2573) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bd29cd455..5d9cede7c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.1.5" +towny = "0.100.1.10" plotsquared = "7.3.2" # Third party From 000b41331637c0a92b15d7234b3e93c9d231533b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 15:12:17 +0100 Subject: [PATCH 127/466] Update dependency gradle to v8.6 (#2577) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew.bat | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1af9e0930..a80b22ce5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew.bat b/gradlew.bat index 6689b85be..7101f8e46 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -43,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail From a52924e03f8a45aba8a28817db214c2f3316c486 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 15:14:06 +0100 Subject: [PATCH 128/466] Update plugin xyz.jpenilla.run-paper to v2.2.3 (#2576) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index ad62a28c1..20c957a9d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,7 +7,7 @@ import xyz.jpenilla.runpaper.task.RunServer plugins { id("io.github.gradle-nexus.publish-plugin") version "1.3.0" - id("xyz.jpenilla.run-paper") version "2.2.2" + id("xyz.jpenilla.run-paper") version "2.2.3" } if (!File("$rootDir/.git").exists()) { From 63689d8cd87462684ef70b05fa863988aa9ba0f8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 15:15:03 +0100 Subject: [PATCH 129/466] Update piston to v0.5.8 (#2574) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5d9cede7c..4280b03ff 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -43,7 +43,7 @@ serverlib = "2.3.4" ## Internal text-adapter = "3.0.6" text = "3.0.4" -piston = "0.5.7" +piston = "0.5.8" # Tests mockito = "5.10.0" From e13ef63c6533ad054b19aa99b983626903009f0c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 15:28:54 +0100 Subject: [PATCH 130/466] Update plotsquared to v7.3.3 (#2575) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4280b03ff..ced8af919 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" towny = "0.100.1.10" -plotsquared = "7.3.2" +plotsquared = "7.3.3" # Third party bstats = "3.0.2" From 4ef4b874984e5bb5bd9622d3060292864b4e2865 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 15:29:22 +0100 Subject: [PATCH 131/466] Update release-drafter/release-drafter action to v6 (#2578) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 90248b436..131fb810e 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -12,6 +12,6 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter@v5 + - uses: release-drafter/release-drafter@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 974078c2cd0ed65e19ecef80a3f81d0dd0cff72a Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Tue, 6 Feb 2024 21:45:25 +0100 Subject: [PATCH 132/466] Release 2.9.2 Signed-off-by: Alexander Brandes --- build.gradle.kts | 4 ++-- .../src/main/java/com/fastasyncworldedit/core/FaweCache.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 20c957a9d..fb3256d36 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.8.5") +var rootVersion by extra("2.9.0") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s-%s", rootVersion, buildNumber) +version = String.format("%s", rootVersion) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java index f5cc88284..46a3a1574 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java @@ -626,7 +626,7 @@ public enum FaweCache implements Trimable { * Create a new blocking executor with specified name and FaweCache logger * * @return new blocking executor - * @since TODO + * @since 2.9.0 */ public ThreadPoolExecutor newBlockingExecutor(String name) { return newBlockingExecutor(name, LOGGER); @@ -636,7 +636,7 @@ public enum FaweCache implements Trimable { * Create a new blocking executor with specified name and logger * * @return new blocking executor - * @since TODO + * @since 2.9.0 */ public ThreadPoolExecutor newBlockingExecutor(String name, Logger logger) { int nThreads = Settings.settings().QUEUE.PARALLEL_THREADS; From c93ec878fa1f4c04f7e3a783a425171c587a958a Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Tue, 6 Feb 2024 23:09:06 +0100 Subject: [PATCH 133/466] Back to snapshot for development Signed-off-by: Alexander Brandes --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index fb3256d36..84685390e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.9.0") +var rootVersion by extra("2.9.1") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s", rootVersion) +version = String.format("%s-%s", rootVersion, buildNumber) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From f94b96d5b2dbc9863bc183bb3764b8158601add2 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sun, 18 Feb 2024 09:55:06 +0100 Subject: [PATCH 134/466] Use actual radius for inverse and adjust inside region check (#2582) --- .../java/com/sk89q/worldedit/regions/CylinderRegion.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java index 03b38a55c..6439d6079 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java @@ -141,7 +141,7 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { */ public void setRadius(Vector2 radius) { this.radius = radius.add(0.5, 0.5); - this.radiusInverse = Vector2.ONE.divide(radius); + this.radiusInverse = Vector2.ONE.divide(this.radius); } /** @@ -413,11 +413,12 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { final IChunk chunk, final Filter filter, final ChunkFilterBlock block, final IChunkGet get, final IChunkSet set, boolean full ) { - int bcx = chunk.getX() >> 4; - int bcz = chunk.getZ() >> 4; + int bcx = chunk.getX() << 4; + int bcz = chunk.getZ() << 4; int tcx = bcx + 15; int tcz = bcz + 15; - if (contains(bcx, bcz) && contains(tcx, tcz)) { + // must contain all 4 corners for fast path + if (contains(bcx, bcz) && contains(tcx, tcz) && contains(bcx, tcz) && contains(tcx, bcz)) { filter(chunk, filter, block, get, set, minY, maxY, full); return; } From 5a749b3b2ce531baa9a95622811600f1dde8afa3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 2 Mar 2024 12:00:21 +0100 Subject: [PATCH 135/466] Update dependency org.mockito:mockito-core to v5.11.0 (#2601) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- worldedit-sponge/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ced8af919..513d46a23 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -46,7 +46,7 @@ text = "3.0.4" piston = "0.5.8" # Tests -mockito = "5.10.0" +mockito = "5.11.0" # Gradle plugins pluginyml = "0.6.0" diff --git a/worldedit-sponge/build.gradle.kts b/worldedit-sponge/build.gradle.kts index c37fe591e..6498cca7e 100644 --- a/worldedit-sponge/build.gradle.kts +++ b/worldedit-sponge/build.gradle.kts @@ -28,7 +28,7 @@ dependencies { }) api("org.apache.logging.log4j:log4j-api") api("org.bstats:bstats-sponge:1.7") - testImplementation("org.mockito:mockito-core:5.10.0") + testImplementation("org.mockito:mockito-core:5.11.0") } <<<<<<< HEAD From c74486f1403b74b174f59015018d78bc8e54ea3d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 2 Mar 2024 12:00:40 +0100 Subject: [PATCH 136/466] Update dependency net.kyori:adventure-nbt to v4.16.0 (#2600) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index 5a9273371..1a922b7af 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -178,7 +178,7 @@ tasks.named("shadowJar") { include(dependency("org.lz4:lz4-java:1.8.0")) } relocate("net.kyori", "com.fastasyncworldedit.core.adventure") { - include(dependency("net.kyori:adventure-nbt:4.15.0")) + include(dependency("net.kyori:adventure-nbt:4.16.0")) } relocate("com.zaxxer", "com.fastasyncworldedit.core.math") { include(dependency("com.zaxxer:SparseBitSet:1.3")) From dbc84a4565311d8f68b98d3846e99f8cb3d8c046 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 2 Mar 2024 12:01:09 +0100 Subject: [PATCH 137/466] Update adventure to v4.16.0 (#2599) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 513d46a23..48443e60e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -21,7 +21,7 @@ plotsquared = "7.3.3" bstats = "3.0.2" sparsebitset = "1.3" parallelgzip = "1.0.5" -adventure = "4.15.0" +adventure = "4.16.0" adventure-bukkit = "4.3.2" checkerqual = "3.42.0" truezip = "6.8.4" From d62e631ce3e0789679a9349c3076ec321f3891b6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 2 Mar 2024 12:01:49 +0100 Subject: [PATCH 138/466] Update plotsquared to v7.3.5 (#2598) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 48443e60e..264ff5a59 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" towny = "0.100.1.10" -plotsquared = "7.3.3" +plotsquared = "7.3.5" # Third party bstats = "3.0.2" From 7af7c28a9ae5ef7ffe57dd31d680a2d2c9c7a0fa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 2 Mar 2024 12:02:08 +0100 Subject: [PATCH 139/466] Update dependency org.ajoberstar.grgit:grgit-gradle to v5.2.2 (#2596) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index fdb47a435..e4227d576 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -22,7 +22,7 @@ val properties = Properties().also { props -> dependencies { implementation(gradleApi()) - implementation("org.ajoberstar.grgit:grgit-gradle:5.2.1") + implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2") implementation("com.github.johnrengelman:shadow:8.1.1") implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.11") } From 3a9bbb72932ef9740111830364cb942165b8bf8e Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sat, 2 Mar 2024 12:31:25 +0100 Subject: [PATCH 140/466] Update renovate.json --- .github/renovate.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/renovate.json b/.github/renovate.json index 740d991fb..3d0f91b5a 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -33,9 +33,6 @@ "Renovate" ], "rebaseWhen" : "conflicted", - "schedule" : [ - "on the first day of the month" - ], "customManagers" : [ { "customType" : "regex", From f5dfe3ae168c8225ef57e44ad4cd1b2b20f49880 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sat, 2 Mar 2024 13:43:38 +0100 Subject: [PATCH 141/466] fix rollback database query (#2591) --- .../core/database/RollbackDatabase.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java index 603e8061a..1677521fe 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java @@ -159,18 +159,23 @@ public class RollbackDatabase extends AsyncNotifyQueue { Future future = call(() -> { try { int count = 0; - String stmtStr; + String stmtStr = """ + SELECT * FROM `%sedits` + WHERE `time` > ? + AND `x2` >= ? + AND `x1` <= ? + AND `z2` >= ? + AND `z1` <= ? + AND `y2` >= ? + AND `y1` <= ? + """; + if (uuid != null) { + stmtStr += "\n AND `player`= ?"; + } if (ascending) { - if (uuid == null) { - stmtStr = "SELECT * FROM`%sedits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND " + - "`y2`>=? AND `y1`<=? ORDER BY `time` , `id`"; - } else { - stmtStr = "SELECT * FROM`%sedits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND " + - "`y2`>=? AND `y1`<=? AND `player`=? ORDER BY `time` ASC, `id` ASC"; - } + stmtStr += "\n ORDER BY `time` ASC, `id` ASC"; } else { - stmtStr = "SELECT * FROM`%sedits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND " + - "`y2`>=? AND `y1`<=? AND `player`=? ORDER BY `time` DESC, `id` DESC"; + stmtStr += "\n ORDER BY `time` DESC, `id` DESC"; } try (PreparedStatement stmt = connection.prepareStatement(stmtStr.formatted(this.prefix))) { stmt.setInt(1, (int) (minTime / 1000)); From b6d691d12b1ff5910705c301f0f818e9fb271e25 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 2 Mar 2024 11:02:35 +0000 Subject: [PATCH 142/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.1.17 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 264ff5a59..0119179f7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.1.10" +towny = "0.100.1.17" plotsquared = "7.3.5" # Third party From 164271374b46957775f52aedf7a39bebd3ff3df3 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Mon, 4 Mar 2024 07:31:56 +0100 Subject: [PATCH 143/466] Decrease lock contention in SingleThreadQueueExtent (#2594) * thread local extent * avoid race conditions due to ChunkHolder pooling * clean up JFR events, javadoc * remove ThreadLocalPassthroughExtent --- .../implementation/ParallelQueueExtent.java | 33 +++++++++++++- .../queue/implementation/QueueHandler.java | 2 +- .../SingleThreadQueueExtent.java | 16 +++---- .../implementation/chunk/ChunkHolder.java | 43 +++++++++++-------- .../com/sk89q/worldedit/LocalSession.java | 5 +++ 5 files changed, 67 insertions(+), 32 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java index 2d2b45aae..52e6cf2c6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java @@ -18,6 +18,7 @@ import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.ExistingBlockMask; @@ -45,6 +46,7 @@ import java.util.stream.IntStream; public class ParallelQueueExtent extends PassthroughExtent { private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static final ThreadLocal extents = new ThreadLocal<>(); private final World world; private final QueueHandler handler; @@ -73,10 +75,36 @@ public class ParallelQueueExtent extends PassthroughExtent { this.fastmode = fastmode; } + /** + * Removes the extent currently associated with the calling thread. + */ + public static void clearCurrentExtent() { + extents.remove(); + } + + /** + * Sets the extent associated with the calling thread. + */ + public static void setCurrentExtent(Extent extent) { + extents.set(extent); + } + + private void enter(Extent extent) { + setCurrentExtent(extent); + } + + private void exit() { + clearCurrentExtent(); + } + @Override @SuppressWarnings({"unchecked", "rawtypes"}) public IQueueExtent getExtent() { - return (IQueueExtent) super.getExtent(); + Extent extent = extents.get(); + if (extent == null) { + extent = super.getExtent(); + } + return (IQueueExtent) extent; } @Override @@ -114,6 +142,7 @@ public class ParallelQueueExtent extends PassthroughExtent { final SingleThreadQueueExtent queue = (SingleThreadQueueExtent) getNewQueue(); queue.setFastMode(fastmode); queue.setFaweExceptionArray(faweExceptionReasonsUsed); + enter(queue); synchronized (queue) { try { ChunkFilterBlock block = null; @@ -154,6 +183,8 @@ public class ParallelQueueExtent extends PassthroughExtent { exceptionCount++; LOGGER.warn(message); } + } finally { + exit(); } })).toArray(ForkJoinTask[]::new); // Join filters diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/QueueHandler.java index 956c33fb2..7bdbf4645 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/QueueHandler.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/QueueHandler.java @@ -408,7 +408,7 @@ public abstract class QueueHandler implements Trimable, Runnable { * Sets the current thread's {@link IQueueExtent} instance in the queue pool to null. */ public void unCache() { - queuePool.set(null); + queuePool.remove(); } private IQueueExtent pool() { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java index 132229d1d..6e06ce348 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java @@ -9,7 +9,6 @@ import com.fastasyncworldedit.core.extent.processor.EmptyBatchProcessor; import com.fastasyncworldedit.core.extent.processor.ExtentBatchProcessorHolder; import com.fastasyncworldedit.core.extent.processor.ProcessorScope; import com.fastasyncworldedit.core.internal.exception.FaweException; -import com.fastasyncworldedit.core.queue.IChunk; import com.fastasyncworldedit.core.queue.IChunkCache; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; @@ -48,11 +47,9 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen private static final Logger LOGGER = LogManagerCompat.getLogger(); - // Pool discarded chunks for reuse (can safely be cleared by another thread) - // private static final ConcurrentLinkedQueue CHUNK_POOL = new ConcurrentLinkedQueue<>(); // Chunks currently being queued / worked on - private final Long2ObjectLinkedOpenHashMap chunks = new Long2ObjectLinkedOpenHashMap<>(); - private final ConcurrentLinkedQueue submissions = new ConcurrentLinkedQueue<>(); + private final Long2ObjectLinkedOpenHashMap> chunks = new Long2ObjectLinkedOpenHashMap<>(); + private final ConcurrentLinkedQueue> submissions = new ConcurrentLinkedQueue<>(); private final ReentrantLock getChunkLock = new ReentrantLock(); private World world = null; private int minY = 0; @@ -142,12 +139,10 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen if (!this.initialized) { return; } - if (!this.chunks.isEmpty()) { - getChunkLock.lock(); - for (IChunk chunk : this.chunks.values()) { - chunk.recycle(); - } + getChunkLock.lock(); + try { this.chunks.clear(); + } finally { getChunkLock.unlock(); } this.enabledQueue = true; @@ -234,7 +229,6 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen } } if (chunk.isEmpty()) { - chunk.recycle(); Future result = Futures.immediateFuture(null); return (V) result; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java index 6103a1649..a7417eddf 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java @@ -1,7 +1,5 @@ package com.fastasyncworldedit.core.queue.implementation.chunk; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock; import com.fastasyncworldedit.core.extent.processor.EmptyBatchProcessor; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; @@ -11,36 +9,34 @@ import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; -import com.fastasyncworldedit.core.queue.Pool; +import com.fastasyncworldedit.core.queue.implementation.ParallelQueueExtent; import com.fastasyncworldedit.core.util.MemUtil; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; 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 org.apache.logging.log4j.Logger; import javax.annotation.Nullable; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; /** * An abstract {@link IChunk} class that implements basic get/set blocks. */ @SuppressWarnings("rawtypes") public class ChunkHolder> implements IQueueChunk { - - private static final Pool POOL = FaweCache.INSTANCE.registerPool( - ChunkHolder.class, - ChunkHolder::new, - Settings.settings().QUEUE.POOL - ); + private static final Logger LOGGER = LogManagerCompat.getLogger(); public static ChunkHolder newInstance() { - return POOL.poll(); + return new ChunkHolder(); } private volatile IChunkGet chunkExisting; // The existing chunk (e.g. a clipboard, or the world, before changes) @@ -63,16 +59,12 @@ public class ChunkHolder> implements IQueueChunk { this.delegate = delegate; } + private static final AtomicBoolean recycleWarning = new AtomicBoolean(false); @Override - public synchronized void recycle() { - delegate = NULL; - if (chunkSet != null) { - chunkSet.recycle(); - chunkSet = null; + public void recycle() { + if (!recycleWarning.getAndSet(true)) { + LOGGER.warn("ChunkHolder should not be recycled.", new Exception()); } - chunkExisting = null; - extent = null; - POOL.offer(this); } public long initAge() { @@ -1018,7 +1010,6 @@ public class ChunkHolder> implements IQueueChunk { // Do nothing }); } - recycle(); return null; } @@ -1031,6 +1022,7 @@ public class ChunkHolder> implements IQueueChunk { IChunkGet get = getOrCreateGet(); try { get.lockCall(); + trackExtent(); boolean postProcess = !(getExtent().getPostProcessor() instanceof EmptyBatchProcessor); final int copyKey = get.setCreateCopy(postProcess); final IChunkSet iChunkSet = getExtent().processSet(this, get, set); @@ -1046,11 +1038,24 @@ public class ChunkHolder> implements IQueueChunk { return get.call(set, finalizer); } finally { get.unlockCall(); + untrackExtent(); } } return null; } + // "call" can be called by QueueHandler#blockingExecutor. In such case, we still want the other thread + // to use this SingleThreadQueueExtent. Otherwise, many threads might end up locking on **one** STQE. + // This way, locking is spread across multiple STQEs, allowing for better performance + + private void trackExtent() { + ParallelQueueExtent.setCurrentExtent(extent); + } + + private void untrackExtent() { + ParallelQueueExtent.clearCurrentExtent(); + } + /** * Get the extent this chunk is in. */ 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 67bbff7af..a00b26702 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -32,6 +32,7 @@ import com.fastasyncworldedit.core.internal.io.FaweOutputStream; import com.fastasyncworldedit.core.limit.FaweLimit; import com.fastasyncworldedit.core.util.BrushCache; import com.fastasyncworldedit.core.util.MainUtil; +import com.fastasyncworldedit.core.util.MaskTraverser; import com.fastasyncworldedit.core.util.StringMan; import com.fastasyncworldedit.core.util.TaskManager; import com.fastasyncworldedit.core.util.TextureHolder; @@ -53,6 +54,7 @@ import com.sk89q.worldedit.command.tool.Tool; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Locatable; +import com.sk89q.worldedit.extent.NullExtent; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.inventory.BlockBag; @@ -594,6 +596,9 @@ public class LocalSession implements TextureHolder { long size = MainUtil.getSize(item); historySize -= size; } + // free the mask from any remaining references to e.g. extents + // if used again + new MaskTraverser(mask).reset(NullExtent.INSTANCE); } finally { historyWriteLock.unlock(); } From 641297497abf26886f2f11f24d2978143fad5c33 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Mon, 4 Mar 2024 07:32:33 +0100 Subject: [PATCH 144/466] Maintain insertion order for RandomPattern sub-patterns (#2603) --- .../core/util/collection/RandomCollection.java | 2 +- .../com/sk89q/worldedit/function/pattern/RandomPattern.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/RandomCollection.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/RandomCollection.java index a157ebd7c..6214777e5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/RandomCollection.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/RandomCollection.java @@ -33,7 +33,7 @@ public abstract class RandomCollection { public static RandomCollection of(Map weights, SimpleRandom random) { checkNotNull(random); return FastRandomCollection.create(weights, random) - .orElse(new SimpleRandomCollection<>(weights, random)); + .orElseGet(() -> new SimpleRandomCollection<>(weights, random)); } public void setRandom(SimpleRandom random) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java index 0568fd5b8..1d2df7223 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java @@ -27,7 +27,7 @@ import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; @@ -41,7 +41,7 @@ public class RandomPattern extends AbstractPattern { //FAWE start - SimpleRandom > Random, LHS

> List private final SimpleRandom random; - private Map weights = new HashMap<>(); + private Map weights = new LinkedHashMap<>(); private RandomCollection collection; private LinkedHashSet patterns = new LinkedHashSet<>(); //FAWE end From eca4dbdca1df8a02fc073f57f9bc84960207d9e6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 21:56:45 +0000 Subject: [PATCH 145/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.1.18 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0119179f7..c55c9169c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.1.17" +towny = "0.100.1.18" plotsquared = "7.3.5" # Third party From 9fa3385edccfeee1dc40a1e4d91aa657ea523bc5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 9 Mar 2024 13:02:30 +0000 Subject: [PATCH 146/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.1.19 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c55c9169c..414e204f5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.1.18" +towny = "0.100.1.19" plotsquared = "7.3.5" # Third party From e682917c437096885b84332cf421d62fc395bcf8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 10 Mar 2024 18:53:53 +0000 Subject: [PATCH 147/466] Update plotsquared to v7.3.6 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 414e204f5..19a0bd368 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" towny = "0.100.1.19" -plotsquared = "7.3.5" +plotsquared = "7.3.6" # Third party bstats = "3.0.2" From 1053d467a43c215083908679d16b5d4727cadf40 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:47:53 +0000 Subject: [PATCH 148/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.1.20 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 19a0bd368..a6acb6c2e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.1.19" +towny = "0.100.1.20" plotsquared = "7.3.6" # Third party From facd31ce31fc31b7a6e7fdbed5b81777231aaf13 Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 14 Mar 2024 17:56:08 +0100 Subject: [PATCH 149/466] fix: do not forcefully direct to x,y,z methods in AbstractDelegateExtent (#2614) - we probably shouldn't be doing this --- .../extent/AbstractDelegateExtent.java | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java index 768af09c1..f2d7dc884 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -91,9 +91,7 @@ public class AbstractDelegateExtent implements Extent { @Override public BlockState getBlock(BlockVector3 position) { - //FAWE start - return coordinates - return extent.getBlock(position.getX(), position.getY(), position.getZ()); - //FAWE end + return extent.getBlock(position); } @Override @@ -103,9 +101,7 @@ public class AbstractDelegateExtent implements Extent { @Override public BaseBlock getFullBlock(BlockVector3 position) { - //FAWE start - return coordinates - return extent.getFullBlock(position.getX(), position.getY(), position.getZ()); - //FAWE end + return extent.getFullBlock(position); } //FAWE start @@ -117,9 +113,7 @@ public class AbstractDelegateExtent implements Extent { @Override public BaseBlock getFullBlock(int x, int y, int z) { - //FAWE start - return coordinates return extent.getFullBlock(x, y, z); - //FAWE end } @Override @@ -375,9 +369,7 @@ public class AbstractDelegateExtent implements Extent { @Override public BiomeType getBiome(BlockVector3 position) { - //FAWE start - switch top x,y,z - return extent.getBiomeType(position.getX(), position.getY(), position.getZ()); - //FAWE end + return extent.getBiome(position); } //FAWE start @@ -420,9 +412,7 @@ public class AbstractDelegateExtent implements Extent { @Override public > boolean setBlock(BlockVector3 position, T block) throws WorldEditException { - //FAWE start - switch to x,y,z - return extent.setBlock(position.getX(), position.getY(), position.getZ(), block); - //FAWE end + return extent.setBlock(position, block); } //FAWE start @@ -447,9 +437,7 @@ public class AbstractDelegateExtent implements Extent { @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { - //FAWE start - switch to x,y,z - return extent.setBiome(position.getX(), position.getY(), position.getZ(), biome); - //FAWE end + return extent.setBiome(position, biome); } //FAWE start From df9527b0b7c4a686b6496dae26661392356d74fa Mon Sep 17 00:00:00 2001 From: MineFact <66020920+MineFact@users.noreply.github.com> Date: Fri, 15 Mar 2024 11:27:25 +0100 Subject: [PATCH 150/466] fix: set and clone Expression Environment after Expression cloning (#2617) - Fixes #2616 --- .../sk89q/worldedit/internal/expression/Expression.java | 5 ++++- .../internal/expression/ExpressionEnvironment.java | 5 ++++- .../regions/shape/WorldEditExpressionEnvironment.java | 9 +++++++-- .../internal/expression/BaseExpressionTest.java | 5 +++++ 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java index b7ce1acf3..23ba96a88 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 @@ -24,6 +24,7 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.antlr.ExpressionLexer; import com.sk89q.worldedit.antlr.ExpressionParser; import com.sk89q.worldedit.internal.expression.invoke.ExpressionCompiler; +import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; @@ -199,7 +200,9 @@ public class Expression implements Cloneable { //FAWE start public Expression clone() { - return new Expression(initialExpression, new HashSet<>(providedSlots)); + Expression expression = new Expression(initialExpression, new HashSet<>(providedSlots)); + expression.setEnvironment(getEnvironment().clone()); + return expression; } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionEnvironment.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionEnvironment.java index 061a520a9..5e44d9da1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionEnvironment.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionEnvironment.java @@ -22,7 +22,7 @@ package com.sk89q.worldedit.internal.expression; /** * Represents a way to access blocks in a world. Has to accept non-rounded coordinates. */ -public interface ExpressionEnvironment { +public interface ExpressionEnvironment extends Cloneable { int getBlockType(double x, double y, double z); @@ -36,4 +36,7 @@ public interface ExpressionEnvironment { int getBlockDataRel(double x, double y, double z); + // FAWE start + ExpressionEnvironment clone(); + // FAWE end } 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 15e93c7db..4b87ebcc6 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 @@ -28,6 +28,8 @@ import com.sk89q.worldedit.math.Vector3; public class WorldEditExpressionEnvironment implements ExpressionEnvironment { + private static final Vector3 BLOCK_CENTER_OFFSET = Vector3.at(0.5, 0.5, 0.5); + private final Vector3 unit; private final Vector3 zero2; //FAWE start - MutableVector3 @@ -42,7 +44,7 @@ public class WorldEditExpressionEnvironment implements ExpressionEnvironment { public WorldEditExpressionEnvironment(Extent extent, Vector3 unit, Vector3 zero) { this.extent = extent; this.unit = unit; - this.zero2 = zero.add(0.5, 0.5, 0.5); + this.zero2 = zero.add(BLOCK_CENTER_OFFSET); } public BlockVector3 toWorld(double x, double y, double z) { @@ -94,10 +96,13 @@ public class WorldEditExpressionEnvironment implements ExpressionEnvironment { public Vector3 toWorldRel(double x, double y, double z) { return current.add(x, y, z); } + + public WorldEditExpressionEnvironment clone() { + return new WorldEditExpressionEnvironment(extent, unit, zero2.subtract(BLOCK_CENTER_OFFSET)); + } //FAWe end public void setCurrentBlock(Vector3 current) { this.current = current; } - } 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 index 3491347a4..3c8ba65d6 100644 --- 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 @@ -114,6 +114,11 @@ class BaseExpressionTest { public int getBlockDataRel(double x, double y, double z) { return (int) y * 100; } + + @Override + public ExpressionEnvironment clone() { + return this; + } }); return expression.evaluate(); From 8363badf8015b58475b500f2814ed05b290f6ac1 Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 15 Mar 2024 18:39:35 +0100 Subject: [PATCH 151/466] fix: correctly (de)serialise ItemType (#2620) - InternalId changes depending on ~~magic~~ so we should not store this value - fixes #2589 --- .../sk89q/worldedit/util/gson/GsonUtil.java | 3 +++ .../worldedit/util/gson/ItemTypeAdapter.java | 26 +++++++++++++++++++ .../sk89q/worldedit/world/item/ItemType.java | 2 +- 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/ItemTypeAdapter.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java index 9b9a9a6e5..d31750e11 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java @@ -23,6 +23,8 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.item.ItemTypes; /** * Utility methods for Google's GSON library. @@ -41,6 +43,7 @@ public final class GsonUtil { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter()); gsonBuilder.registerTypeAdapter(BlockVector3.class, new BlockVectorAdapter()); + gsonBuilder.registerTypeAdapter(ItemType.class, new ItemTypeAdapter()); return gsonBuilder; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/ItemTypeAdapter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/ItemTypeAdapter.java new file mode 100644 index 000000000..5f8d6d9a2 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/ItemTypeAdapter.java @@ -0,0 +1,26 @@ +package com.sk89q.worldedit.util.gson; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.item.ItemTypes; + +import java.lang.reflect.Type; + +public final class ItemTypeAdapter implements JsonDeserializer { + + @Override + public ItemType deserialize(JsonElement json, Type type, JsonDeserializationContext cont) throws JsonParseException { + JsonObject jsonObject = json.getAsJsonObject(); + String id = jsonObject.get("id").getAsString(); + ItemType itemType = ItemTypes.get(id); + if (itemType == null) { + throw new JsonParseException("Could not parse item type `" + id + "`"); + } + return itemType; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java index 5a1e7653f..16a65c308 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java @@ -79,7 +79,7 @@ public class ItemType implements RegistryItem, Keyed { } //FAWE start - private int internalId; + private transient int internalId; @Override public void setInternalId(int internalId) { From 10dc64eeaf5693cf2d1e4064c045cd36262cf42a Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Fri, 15 Mar 2024 18:41:16 +0100 Subject: [PATCH 152/466] Make sure to process all chunks in PQE even if PARALLEL_THREADS = 1 (#2611) make sure to process all chunks in PQE even if PARALLEL_THREADS = 1 --- .../core/queue/implementation/ParallelQueueExtent.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java index 52e6cf2c6..e88a9ccd3 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java @@ -131,9 +131,12 @@ public class ParallelQueueExtent extends PassthroughExtent { // Get a pool, to operate on the chunks in parallel final int size = Math.min(chunks.size(), Settings.settings().QUEUE.PARALLEL_THREADS); - if (size <= 1 && chunksIter.hasNext()) { - BlockVector2 pos = chunksIter.next(); - getExtent().apply(null, filter, region, pos.getX(), pos.getZ(), full); + if (size <= 1) { + // if PQE is ever used with PARALLEL_THREADS = 1, or only one chunk is edited, just run sequentially + while (chunksIter.hasNext()) { + BlockVector2 pos = chunksIter.next(); + getExtent().apply(null, filter, region, pos.getX(), pos.getZ(), full); + } } else { final ForkJoinTask[] tasks = IntStream.range(0, size).mapToObj(i -> handler.submit(() -> { try { From 37d4e9bb6f431204ceccb59b836de9e5358c7acb Mon Sep 17 00:00:00 2001 From: Zeranny Date: Fri, 15 Mar 2024 17:41:53 +0000 Subject: [PATCH 153/466] Allow factory suggestions to have parser context (#2613) * Add context to rich parser * Description for getSuggestions with context * Tidy up imports * Swap which getSuggestions is primary * Revert "Swap which getSuggestions is primary" This reverts commit 5c257f60ea9ec002e407b2a4a8a7c6ede6bee5e7. * Revert default swap and add deprecation note --- .../extension/factory/parser/RichParser.java | 25 ++++++++++++++++--- .../factory/parser/mask/RichMaskParser.java | 8 +++--- .../command/argument/FactoryConverter.java | 14 ++++++++--- .../extension/factory/MaskFactory.java | 6 ++--- .../internal/registry/AbstractFactory.java | 7 +++++- .../internal/registry/InputParser.java | 13 ++++++++++ 6 files changed, 58 insertions(+), 15 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/RichParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/RichParser.java index 617143495..30dad8f37 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/RichParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/RichParser.java @@ -53,7 +53,7 @@ public abstract class RichParser extends InputParser implements AliasedPar } @Nonnull - private Function> extractArguments(String input) { + private Function> extractArguments(String input, ParserContext context) { return prefix -> { if (input.length() > prefix.length() && input.startsWith(prefix + "[")) { // input already contains argument(s) -> extract them @@ -65,7 +65,7 @@ public abstract class RichParser extends InputParser implements AliasedPar } String previous = prefix + builder; // read the suggestions for the last argument - return getSuggestions(strings[strings.length - 1], strings.length - 1) + return getSuggestions(strings[strings.length - 1], strings.length - 1, context) .map(suggestion -> previous + "[" + suggestion); } else { return Stream.of(prefix); @@ -95,7 +95,7 @@ public abstract class RichParser extends InputParser implements AliasedPar public Stream getSuggestions(String input) { return Arrays.stream(this.prefixes) .filter(validPrefix(input)) - .flatMap(extractArguments(input)); + .flatMap(extractArguments(input, new ParserContext())); } @Override @@ -122,8 +122,25 @@ public abstract class RichParser extends InputParser implements AliasedPar * @param argumentInput the already provided input for the argument at the given index. * @param index the index of the argument to get suggestions for. * @return a stream of suggestions matching the given input for the argument at the given index. + * + * @deprecated Use the version that takes a {@link ParserContext}, {@link #getSuggestions(String, int, ParserContext)} */ - protected abstract Stream getSuggestions(String argumentInput, int index); + @Deprecated + protected Stream getSuggestions(String argumentInput, int index) { + return Stream.empty(); + } + + /** + * Returns a stream of suggestions for the argument at the given index. + * + * @param argumentInput the already provided input for the argument at the given index. + * @param index the index of the argument to get suggestions for. + * @param context the context which may optionally be provided by a parser. + * @return a stream of suggestions matching the given input for the argument at the given index. + */ + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { + return getSuggestions(argumentInput, index); + } /** * Parses the already split arguments. diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java index 4e0fbfa91..84437c19a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java @@ -97,11 +97,11 @@ public class RichMaskParser extends FaweParser { )), () -> { if (full.length() == 1) { - return new ArrayList<>(worldEdit.getMaskFactory().getSuggestions("")); + return new ArrayList<>(worldEdit.getMaskFactory().getSuggestions("", context)); } return new ArrayList<>(worldEdit .getMaskFactory() - .getSuggestions(command.toLowerCase(Locale.ROOT))); + .getSuggestions(command.toLowerCase(Locale.ROOT), context)); } ); } @@ -164,11 +164,11 @@ public class RichMaskParser extends FaweParser { )), () -> { if (full.length() == 1) { - return new ArrayList<>(worldEdit.getMaskFactory().getSuggestions("")); + return new ArrayList<>(worldEdit.getMaskFactory().getSuggestions("", context)); } return new ArrayList<>(worldEdit .getMaskFactory() - .getSuggestions(command.toLowerCase(Locale.ROOT))); + .getSuggestions(command.toLowerCase(Locale.ROOT), context)); } ); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java index 1a382d43c..d82d25394 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java @@ -113,8 +113,7 @@ public class FactoryConverter implements ArgumentConverter { ); } - @Override - public ConversionResult convert(String argument, InjectedValueAccess context) { + private ParserContext createContext(InjectedValueAccess context) { Actor actor = context.injectedValue(Key.of(Actor.class)) .orElseThrow(() -> new IllegalStateException("No actor")); LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor); @@ -139,6 +138,13 @@ public class FactoryConverter implements ArgumentConverter { contextTweaker.accept(parserContext); } + return parserContext; + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + ParserContext parserContext = createContext(context); + try { return SuccessfulConversion.fromSingle( factoryExtractor.apply(worldEdit).parseFromInput(argument, parserContext) @@ -150,7 +156,9 @@ public class FactoryConverter implements ArgumentConverter { @Override public List getSuggestions(String input, InjectedValueAccess context) { - return factoryExtractor.apply(worldEdit).getSuggestions(input); + ParserContext parserContext = createContext(context); + + return factoryExtractor.apply(worldEdit).getSuggestions(input, parserContext); } @Override 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 24c674f0b..5c8ff7d6f 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 @@ -127,13 +127,13 @@ public final class MaskFactory extends AbstractFactory { } @Override - public List getSuggestions(String input) { + public List getSuggestions(String input, final ParserContext parserContext) { 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(split[split.length - 1], parserContext).stream().map(s -> prev + s).collect(Collectors.toList()); } - return super.getSuggestions(input); + return super.getSuggestions(input, parserContext); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java index ef4299b33..237dd1c4c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java @@ -96,9 +96,14 @@ public abstract class AbstractFactory { throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input))); } + @Deprecated public List getSuggestions(String input) { + return getSuggestions(input, new ParserContext()); + } + + public List getSuggestions(String input, ParserContext context) { return parsers.stream().flatMap( - p -> p.getSuggestions(input) + p -> p.getSuggestions(input, context) ).collect(Collectors.toList()); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java index 87829a272..57ec3a247 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 @@ -45,9 +45,22 @@ public abstract class InputParser { * Gets a stream of suggestions of input to this parser. * * @return a stream of suggestions + * @deprecated Use the version that takes a {@link ParserContext}, {@link #getSuggestions(String, ParserContext)} */ + @Deprecated public Stream getSuggestions(String input) { return Stream.empty(); } + /** + * Gets a stream of suggestions of input to this parser. + * + * @param input The string input + * @param context The parser context + * + * @return a stream of suggestions + */ + public Stream getSuggestions(String input, ParserContext context) { + return getSuggestions(input); + } } From 84f661d57f595d5b80ffb81e8cc26172634b420d Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Fri, 15 Mar 2024 23:37:02 +0100 Subject: [PATCH 154/466] Release 2.9.1 Signed-off-by: Alexander Brandes --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 84685390e..9d5734134 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s-%s", rootVersion, buildNumber) +version = String.format("%s", rootVersion) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From bb9a0d27f26903f768ba72c729ee3d5f221e8775 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Fri, 15 Mar 2024 23:48:14 +0100 Subject: [PATCH 155/466] Back to snapshot for development Signed-off-by: Alexander Brandes --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 9d5734134..c5c27082b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.9.1") +var rootVersion by extra("2.9.2") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s", rootVersion) +version = String.format("%s-%s", rootVersion, buildNumber) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From f60539f41ddd6d917b52f6119274c1985dcff2b4 Mon Sep 17 00:00:00 2001 From: Jordan Date: Sat, 16 Mar 2024 20:12:02 +0100 Subject: [PATCH 156/466] chore: deprecate transform extent for removal (#2623) --- .../com/fastasyncworldedit/core/extent/TransformExtent.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java index 91b99b025..64b940d97 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java @@ -12,6 +12,10 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +/** + * @deprecated Unused internal, will be removed in v3 + */ +@Deprecated(forRemoval = true, since = "TODO") public class TransformExtent extends BlockTransformExtent { private final MutableVector3 mutable1 = new MutableVector3(); From 0db8154546af60ba7c35ea9da627d77051035d65 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 17 Mar 2024 08:37:03 +0100 Subject: [PATCH 157/466] Drop support for 1.17.1 (#2627) Signed-off-by: Alexander Brandes --- .github/ISSUE_TEMPLATE/bug_report.yml | 1 - build.gradle.kts | 2 +- settings.gradle.kts | 2 +- .../adapters/adapter-1_17_1/build.gradle.kts | 27 - .../adapter/ext/fawe/PaperweightAdapter.java | 1013 ------ .../ext/fawe/PaperweightDataConverters.java | 2961 ----------------- .../ext/fawe/PaperweightFakePlayer.java | 103 - .../fawe/PaperweightWorldNativeAccess.java | 209 -- .../v1_17_R1_2/PaperweightBlockMaterial.java | 189 -- .../v1_17_R1_2/PaperweightFaweAdapter.java | 671 ---- .../PaperweightFaweWorldNativeAccess.java | 286 -- .../fawe/v1_17_R1_2/PaperweightGetBlocks.java | 1096 ------ .../v1_17_R1_2/PaperweightGetBlocks_Copy.java | 251 -- .../v1_17_R1_2/PaperweightMapChunkUtil.java | 32 - .../PaperweightPlatformAdapter.java | 526 --- .../v1_17_R1_2/PaperweightPostProcessor.java | 175 - .../PaperweightStarlightRelighter.java | 113 - .../PaperweightStarlightRelighterFactory.java | 26 - .../nbt/PaperweightLazyCompoundTag.java | 161 - .../v1_17_R1_2/regen/PaperweightRegen.java | 694 ---- worldedit-bukkit/build.gradle.kts | 2 +- .../bukkit/BukkitServerInterface.java | 3 - .../core/configuration/Settings.java | 8 +- 23 files changed, 4 insertions(+), 8547 deletions(-) delete mode 100644 worldedit-bukkit/adapters/adapter-1_17_1/build.gradle.kts delete mode 100644 worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightDataConverters.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightFakePlayer.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightWorldNativeAccess.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightBlockMaterial.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweAdapter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweWorldNativeAccess.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightMapChunkUtil.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPostProcessor.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighterFactory.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/nbt/PaperweightLazyCompoundTag.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index b687075ad..bc78076bd 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -31,7 +31,6 @@ body: - '1.20' - '1.19.4' - '1.18.2' - - '1.17.1' validations: required: true diff --git a/build.gradle.kts b/build.gradle.kts index c5c27082b..15845439a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -83,7 +83,7 @@ allprojects { } applyCommonConfiguration() -val supportedVersions = listOf("1.17.1", "1.18.2", "1.19.4", "1.20", "1.20.4") +val supportedVersions = listOf("1.18.2", "1.19.4", "1.20", "1.20.4") tasks { supportedVersions.forEach { diff --git a/settings.gradle.kts b/settings.gradle.kts index 6f9b3e8e0..74cba1396 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,7 +2,7 @@ rootProject.name = "FastAsyncWorldEdit" include("worldedit-libs") -listOf("1_17_1", "1_18_2", "1_19_4", "1_20", "1_20_2", "1_20_4").forEach { +listOf("1_18_2", "1_19_4", "1_20", "1_20_2", "1_20_4").forEach { include("worldedit-bukkit:adapters:adapter-$it") } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_17_1/build.gradle.kts deleted file mode 100644 index 9eb68ea36..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/build.gradle.kts +++ /dev/null @@ -1,27 +0,0 @@ -import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension - -applyPaperweightAdapterConfiguration() - -plugins { - java -} - -repositories { - mavenCentral() - gradlePluginPortal() -} - -java { - toolchain.languageVersion.set(JavaLanguageVersion.of(17)) -} - -configurations.all { - attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) -} - - -dependencies { - // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.17.1-R0.1-SNAPSHOT - the().paperDevBundle("1.17.1-R0.1-20220414.034903-210") - compileOnly(libs.paperlib) -} diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java deleted file mode 100644 index 7d1fcc84e..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java +++ /dev/null @@ -1,1013 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe; - -import com.google.common.base.Preconditions; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.google.common.util.concurrent.Futures; -import com.mojang.datafixers.util.Either; -import com.mojang.serialization.Lifecycle; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.blocks.BaseItem; -import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.PaperweightFaweAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.PaperweightPlatformAdapter; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.extension.platform.Watchdog; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.Constants; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; -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.util.SideEffect; -import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; -import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.ByteBinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; -import com.sk89q.worldedit.util.nbt.EndBinaryTag; -import com.sk89q.worldedit.util.nbt.FloatBinaryTag; -import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; -import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.LongBinaryTag; -import com.sk89q.worldedit.util.nbt.ShortBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; -import com.sk89q.worldedit.world.DataFixer; -import com.sk89q.worldedit.world.RegenOptions; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.BiomeTypes; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.item.ItemType; -import net.minecraft.Util; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Registry; -import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.progress.ChunkProgressListener; -import net.minecraft.util.StringRepresentable; -import net.minecraft.util.thread.BlockableEventLoop; -import net.minecraft.world.Clearable; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelSettings; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.StateDefinition; -import net.minecraft.world.level.block.state.properties.DirectionProperty; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkBiomeContainer; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.WorldGenSettings; -import net.minecraft.world.level.storage.LevelStorageSource; -import net.minecraft.world.level.storage.PrimaryLevelData; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World.Environment; -import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_17_R1.CraftServer; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; -import org.bukkit.generator.ChunkGenerator; -import org.spigotmc.SpigotConfig; -import org.spigotmc.WatchdogThread; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.OptionalInt; -import java.util.OptionalLong; -import java.util.Set; -import java.util.TreeMap; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ForkJoinPool; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -public final class PaperweightAdapter implements BukkitImplAdapter { - - private final Logger LOGGER = Logger.getLogger(getClass().getCanonicalName()); - - private final Field worldsField; - private final Method getChunkFutureMainThreadMethod; - private final Field mainThreadProcessorField; - private final Watchdog watchdog; - - // ------------------------------------------------------------------------ - // Code that may break between versions of Minecraft - // ------------------------------------------------------------------------ - - public PaperweightAdapter() throws NoSuchFieldException, NoSuchMethodException { - // A simple test - CraftServer.class.cast(Bukkit.getServer()); - - int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); - if (dataVersion != 2730) { - throw new UnsupportedClassVersionError("Not 1.17.1!"); - } - - worldsField = CraftServer.class.getDeclaredField("worlds"); - worldsField.setAccessible(true); - - getChunkFutureMainThreadMethod = ServerChunkCache.class.getDeclaredMethod("getChunkFutureMainThread", - int.class, int.class, ChunkStatus.class, boolean.class - ); - getChunkFutureMainThreadMethod.setAccessible(true); - - mainThreadProcessorField = ServerChunkCache.class.getDeclaredField( - Refraction.pickName("mainThreadProcessor", "g") - ); - mainThreadProcessorField.setAccessible(true); - - new PaperweightDataConverters(CraftMagicNumbers.INSTANCE.getDataVersion(), this).build(ForkJoinPool.commonPool()); - - Watchdog watchdog; - try { - Class.forName("org.spigotmc.WatchdogThread"); - watchdog = new SpigotWatchdog(); - } catch (ClassNotFoundException | NoSuchFieldException e) { - try { - watchdog = new MojangWatchdog(((CraftServer) Bukkit.getServer()).getServer()); - } catch (NoSuchFieldException ex) { - watchdog = null; - } - } - this.watchdog = watchdog; - - try { - Class.forName("org.spigotmc.SpigotConfig"); - SpigotConfig.config.set("world-settings.faweregentempworld.verbose", false); - } catch (ClassNotFoundException ignored) { - } - } - - @Override - public DataFixer getDataFixer() { - return PaperweightDataConverters.INSTANCE; - } - - /** - * Read the given NBT data into the given tile entity. - * - * @param tileEntity the tile entity - * @param tag the tag - */ - static void readTagIntoTileEntity(net.minecraft.nbt.CompoundTag tag, BlockEntity tileEntity) { - tileEntity.load(tag); - tileEntity.setChanged(); - } - - /** - * Write the tile entity's NBT data to the given tag. - * - * @param tileEntity the tile entity - * @param tag the tag - */ - private static void readTileEntityIntoTag(BlockEntity tileEntity, net.minecraft.nbt.CompoundTag tag) { - tileEntity.save(tag); - } - - /** - * Get the ID string of the given entity. - * - * @param entity the entity - * @return the entity ID - */ - private static String getEntityId(Entity entity) { - return EntityType.getKey(entity.getType()).toString(); - } - - /** - * Create an entity using the given entity ID. - * - * @param id the entity ID - * @param world the world - * @return an entity or null - */ - @Nullable - private static Entity createEntityFromId(String id, net.minecraft.world.level.Level world) { - return EntityType.byString(id).map(t -> t.create(world)).orElse(null); - } - - /** - * Write the given NBT data into the given entity. - * - * @param entity the entity - * @param tag the tag - */ - private static void readTagIntoEntity(net.minecraft.nbt.CompoundTag tag, Entity entity) { - entity.load(tag); - } - - /** - * Write the entity's NBT data to the given tag. - * - * @param entity the entity - * @param tag the tag - */ - private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag tag) { - //FAWE start - avoid villager async catcher - PaperweightPlatformAdapter.readEntityIntoTag(entity, tag); - //FAWE end - } - - private static Block getBlockFromType(BlockType blockType) { - return Registry.BLOCK.get(ResourceLocation.tryParse(blockType.getId())); - } - - private static Item getItemFromType(ItemType itemType) { - return Registry.ITEM.get(ResourceLocation.tryParse(itemType.getId())); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockData data) { - net.minecraft.world.level.block.state.BlockState state = ((CraftBlockData) data).getState(); - int combinedId = Block.getId(state); - return combinedId == 0 && state.getBlock() != Blocks.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockState state) { - Block mcBlock = getBlockFromType(state.getBlockType()); - net.minecraft.world.level.block.state.BlockState newState = mcBlock.defaultBlockState(); - Map, Object> states = state.getStates(); - newState = applyProperties(mcBlock.getStateDefinition(), newState, states); - final int combinedId = Block.getId(newState); - return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); - } - - @Deprecated - @Override - public BlockState getBlock(Location location) { - Preconditions.checkNotNull(location); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - final CraftBlockData blockData = chunk.getBlockState(blockPos).createCraftBlockData(); - BlockState state = BukkitAdapter.adapt(blockData); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - - return state; - } - - @Override - public BaseBlock getFullBlock(Location location) { - BlockState state = getBlock(location); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - - // Read the NBT data - BlockEntity te = chunk.getBlockEntity(blockPos); - if (te != null) { - net.minecraft.nbt.CompoundTag tag = te.save(new net.minecraft.nbt.CompoundTag()); - //FAWE start - BinaryTag - return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); - //FAWE end - } - - return state.toBaseBlock(); - } - - @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightWorldNativeAccess( - this, - new WeakReference<>(((CraftWorld) world).getHandle()) - ); - } - - private static net.minecraft.core.Direction adapt(Direction face) { - switch (face) { - case NORTH: - return net.minecraft.core.Direction.NORTH; - case SOUTH: - return net.minecraft.core.Direction.SOUTH; - case WEST: - return net.minecraft.core.Direction.WEST; - case EAST: - return net.minecraft.core.Direction.EAST; - case DOWN: - return net.minecraft.core.Direction.DOWN; - case UP: - default: - return net.minecraft.core.Direction.UP; - } - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - private net.minecraft.world.level.block.state.BlockState applyProperties( - StateDefinition stateContainer, - net.minecraft.world.level.block.state.BlockState newState, - Map, Object> states - ) { - for (Map.Entry, Object> state : states.entrySet()) { - net.minecraft.world.level.block.state.properties.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.world.level.block.state.properties.EnumProperty) { - String enumName = (String) value; - value = ((net.minecraft.world.level.block.state.properties.EnumProperty) property) - .getValue(enumName).orElseThrow(() -> - new IllegalStateException( - "Enum property " + property.getName() + " does not contain " + enumName - ) - ); - } - - newState = newState.setValue( - (net.minecraft.world.level.block.state.properties.Property) property, - (Comparable) value - ); - } - return newState; - } - - @Override - public BaseEntity getEntity(org.bukkit.entity.Entity entity) { - checkNotNull(entity); - - CraftEntity craftEntity = ((CraftEntity) entity); - Entity mcEntity = craftEntity.getHandle(); - - String id = getEntityId(mcEntity); - - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - readEntityIntoTag(mcEntity, tag); - //FAWE start - BinaryTag - return new BaseEntity( - com.sk89q.worldedit.world.entity.EntityTypes.get(id), - LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag)) - ); - //FAWE end - } - - @Nullable - @Override - public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state) { - checkNotNull(location); - checkNotNull(state); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - ServerLevel worldServer = craftWorld.getHandle(); - - Entity createdEntity = createEntityFromId(state.getType().getId(), craftWorld.getHandle()); - - if (createdEntity != null) { - CompoundTag nativeTag = state.getNbtData(); - if (nativeTag != null) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNative(nativeTag); - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - readTagIntoEntity(tag, createdEntity); - } - - createdEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - - worldServer.addEntity(createdEntity, SpawnReason.CUSTOM); - return createdEntity.getBukkitEntity(); - } else { - return null; - } - } - - @Override - public Component getRichBlockName(BlockType blockType) { - return TranslatableComponent.of(getBlockFromType(blockType).getDescriptionId()); - } - - @Override - public Component getRichItemName(ItemType itemType) { - return TranslatableComponent.of(getItemFromType(itemType).getDescriptionId()); - } - - @Override - public Component getRichItemName(BaseItemStack itemStack) { - return TranslatableComponent.of(CraftItemStack.asNMSCopy(BukkitAdapter.adapt(itemStack)).getDescriptionId()); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private static final LoadingCache> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { - @Override - public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else if (state instanceof DirectionProperty) { - return new DirectionalProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - return new EnumProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else { - throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state.getClass().getSimpleName()); - } - } - }); - - @SuppressWarnings({ "rawtypes" }) - @Override - public Map> getProperties(BlockType blockType) { - Map> properties = new TreeMap<>(); - Block block = getBlockFromType(blockType); - StateDefinition blockStateList = - block.getStateDefinition(); - for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { - Property property = PROPERTY_CACHE.getUnchecked(state); - properties.put(property.getName(), property); - } - return properties; - } - - @Override - public void sendFakeNBT(final Player player, final BlockVector3 pos, final CompoundBinaryTag nbtData) { - - } - - @Override - public void sendFakeOP(Player player) { - ((CraftPlayer) player).getHandle().networkManager.send(new ClientboundEntityEventPacket( - ((CraftPlayer) player).getHandle(), (byte) 28 - )); - } - - @Override - public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { - ItemStack stack = new ItemStack(Registry.ITEM.get(ResourceLocation.tryParse(item.getType().getId())), item.getAmount()); - stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData()))); - return CraftItemStack.asCraftMirror(stack); - } - - @Override - public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { - final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); - final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); - weStack.setNbtData(((CompoundTag) toNative(nmsStack.getTag()))); - return weStack; - } - - private final LoadingCache fakePlayers - = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); - - @Override - public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) { - CraftWorld craftWorld = (CraftWorld) world; - ServerLevel worldServer = craftWorld.getHandle(); - ItemStack stack = CraftItemStack.asNMSCopy(BukkitAdapter.adapt(item instanceof BaseItemStack - ? ((BaseItemStack) item) : new BaseItemStack(item.getType(), item.getNbtData(), 1))); - stack.setTag((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData())); - - PaperweightFakePlayer fakePlayer; - try { - fakePlayer = fakePlayers.get(worldServer); - } catch (ExecutionException ignored) { - return false; - } - fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); - fakePlayer.absMoveTo(position.getBlockX(), position.getBlockY(), position.getBlockZ(), - (float) face.toVector().toYaw(), (float) face.toVector().toPitch() - ); - - final BlockPos blockPos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos); - final net.minecraft.core.Direction enumFacing = adapt(face); - BlockHitResult rayTrace = new BlockHitResult(blockVec, enumFacing, blockPos, false); - UseOnContext context = new UseOnContext(fakePlayer, InteractionHand.MAIN_HAND, rayTrace); - InteractionResult result = stack.placeItem(context, InteractionHand.MAIN_HAND); - if (result != InteractionResult.SUCCESS) { - if (worldServer - .getBlockState(blockPos) - .use(worldServer, fakePlayer, InteractionHand.MAIN_HAND, rayTrace) - .consumesAction()) { - result = InteractionResult.SUCCESS; - } else { - result = stack.getItem().use(worldServer, fakePlayer, InteractionHand.MAIN_HAND).getResult(); - } - } - - return result == InteractionResult.SUCCESS; - } - - @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 position, BlockState blockState) { - int internalId = BlockStateIdAccess.getBlockStateId(blockState); - net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId); - return blockData.canSurvive( - ((CraftWorld) world).getHandle(), - new BlockPos(position.getX(), position.getY(), position.getZ()) - ); - } - - @Override - public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) { - try { - doRegen(bukkitWorld, region, extent, options); - } catch (Exception e) { - throw new IllegalStateException("Regen failed.", e); - } - - return true; - } - - private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { - Environment env = bukkitWorld.getEnvironment(); - ChunkGenerator gen = bukkitWorld.getGenerator(); - - Path tempDir = Files.createTempDirectory("FastAsyncWorldEditWorldGen"); - LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir); - ResourceKey worldDimKey = getWorldDimKey(env); - try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { - ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); - PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() - .getWorldData().overworldData(); - WorldGenSettings originalOpts = levelProperties.worldGenSettings(); - - long seed = options.getSeed().orElse(originalWorld.getSeed()); - WorldGenSettings newOpts = options.getSeed().isPresent() - ? originalOpts.withSeed(levelProperties.isHardcore(), OptionalLong.of(seed)) - : originalOpts; - - LevelSettings newWorldSettings = new LevelSettings( - "faweregentempworld", - levelProperties.settings.gameType(), - levelProperties.settings.hardcore(), - levelProperties.settings.difficulty(), - levelProperties.settings.allowCommands(), - levelProperties.settings.gameRules(), - levelProperties.settings.getDataPackConfig() - ); - PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, Lifecycle.stable()); - - ServerLevel freshWorld = new ServerLevel( - originalWorld.getServer(), - originalWorld.getServer().executor, - session, newWorldData, - originalWorld.dimension(), - originalWorld.dimensionType(), - new NoOpWorldLoadListener(), - newOpts.dimensions().get(worldDimKey).generator(), - originalWorld.isDebug(), - seed, - ImmutableList.of(), - false, - env, gen, - bukkitWorld.getBiomeProvider() - ); - try { - regenForWorld(region, extent, freshWorld, options); - } finally { - freshWorld.getChunkSource().close(false); - } - } finally { - try { - @SuppressWarnings("unchecked") - Map map = (Map) worldsField.get(Bukkit.getServer()); - map.remove("faweregentempworld"); - } catch (IllegalAccessException ignored) { - } - SafeFiles.tryHardToDeleteDir(tempDir); - } - } - - private BiomeType adapt(ServerLevel serverWorld, Biome origBiome) { - ResourceLocation key = serverWorld.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY).getKey(origBiome); - if (key == null) { - return null; - } - return BiomeTypes.get(key.toString()); - } - - @SuppressWarnings("unchecked") - private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld, RegenOptions options) throws - WorldEditException { - List> chunkLoadings = submitChunkLoadTasks(region, serverWorld); - BlockableEventLoop executor; - try { - executor = (BlockableEventLoop) mainThreadProcessorField.get(serverWorld.getChunkSource()); - } catch (IllegalAccessException e) { - throw new IllegalStateException("Couldn't get executor for chunk loading.", e); - } - executor.managedBlock(() -> { - // bail out early if a future fails - if (chunkLoadings.stream().anyMatch(ftr -> - ftr.isDone() && Futures.getUnchecked(ftr) == null - )) { - return false; - } - return chunkLoadings.stream().allMatch(CompletableFuture::isDone); - }); - Map chunks = new HashMap<>(); - for (CompletableFuture future : chunkLoadings) { - @Nullable - ChunkAccess chunk = future.getNow(null); - checkState(chunk != null, "Failed to generate a chunk, regen failed."); - chunks.put(chunk.getPos(), chunk); - } - - for (BlockVector3 vec : region) { - BlockPos pos = new BlockPos(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()); - ChunkAccess chunk = chunks.get(new ChunkPos(pos)); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(pos); - BlockStateHolder state = ((PaperweightFaweAdapter) WorldEditPlugin - .getInstance() - .getBukkitImplAdapter()).adapt(blockData); - Objects.requireNonNull(state); - BlockEntity blockEntity = chunk.getBlockEntity(pos); - if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - blockEntity.save(tag); - //FAWE start - BinaryTag - state = state.toBaseBlock(((CompoundBinaryTag) toNativeBinary(tag))); - //FAWE end - } - extent.setBlock(vec, state.toBaseBlock()); - if (options.shouldRegenBiomes()) { - ChunkBiomeContainer biomeIndex = chunk.getBiomes(); - if (biomeIndex != null) { - Biome origBiome = biomeIndex.getNoiseBiome(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()); - BiomeType adaptedBiome = adapt(serverWorld, origBiome); - if (adaptedBiome != null) { - extent.setBiome(vec, adaptedBiome); - } - } - } - } - } - - @SuppressWarnings("unchecked") - private List> submitChunkLoadTasks(Region region, ServerLevel serverWorld) { - ServerChunkCache chunkManager = serverWorld.getChunkSource(); - List> chunkLoadings = new ArrayList<>(); - // Pre-gen all the chunks - for (BlockVector2 chunk : region.getChunks()) { - try { - chunkLoadings.add( - ((CompletableFuture>) - getChunkFutureMainThreadMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) - .thenApply(either -> either.left().orElse(null)) - ); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalStateException("Couldn't load chunk for regen.", e); - } - } - return chunkLoadings; - } - - private ResourceKey getWorldDimKey(Environment env) { - switch (env) { - case NETHER: - return LevelStem.NETHER; - case THE_END: - return LevelStem.END; - case NORMAL: - default: - return LevelStem.OVERWORLD; - } - } - - private static final Set SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( - SideEffect.NEIGHBORS, - SideEffect.LIGHTING, - SideEffect.VALIDATION, - SideEffect.ENTITY_AI, - SideEffect.EVENTS, - SideEffect.UPDATE - ); - - @Override - public Set getSupportedSideEffects() { - return SUPPORTED_SIDE_EFFECTS; - } - - @Override - public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) { - ServerLevel originalWorld = ((CraftWorld) world).getHandle(); - - BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); - if (entity instanceof Clearable) { - ((Clearable) entity).clearContent(); - return true; - } - return false; - } - - // ------------------------------------------------------------------------ - // Code that is less likely to break - // ------------------------------------------------------------------------ - - /** - * Converts from a non-native NMS NBT structure to a native WorldEdit NBT - * structure. - * - * @param foreign non-native NMS NBT structure - * @return native WorldEdit NBT structure - */ - //FAWE start - BinaryTag - @Override - public BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { - if (foreign == null) { - return null; - } - if (foreign instanceof net.minecraft.nbt.CompoundTag) { - Map values = new HashMap<>(); - Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); - - for (String str : foreignKeys) { - net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); - values.put(str, toNativeBinary(base)); - } - return CompoundBinaryTag.from(values); - } else if (foreign instanceof net.minecraft.nbt.ByteTag) { - return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); - } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { - return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); - } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { - return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); - } else if (foreign instanceof net.minecraft.nbt.FloatTag) { - return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); - } else if (foreign instanceof net.minecraft.nbt.IntTag) { - return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); - } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { - return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); - } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { - return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); - } else if (foreign instanceof net.minecraft.nbt.ListTag) { - try { - return toNativeList((net.minecraft.nbt.ListTag) foreign); - } catch (Throwable e) { - LOGGER.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); - return ListBinaryTag.empty(); - } - } else if (foreign instanceof net.minecraft.nbt.LongTag) { - return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); - } else if (foreign instanceof net.minecraft.nbt.ShortTag) { - return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); - } else if (foreign instanceof net.minecraft.nbt.StringTag) { - return StringBinaryTag.of(foreign.getAsString()); - } else if (foreign instanceof net.minecraft.nbt.EndTag) { - return EndBinaryTag.get(); - } else { - throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); - } - } - - /** - * Convert a foreign NBT list tag into a native WorldEdit one. - * - * @param foreign the foreign tag - * @return the converted tag - * @throws SecurityException on error - * @throws IllegalArgumentException on error - */ - private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { - ListBinaryTag.Builder values = ListBinaryTag.builder(); - - for (net.minecraft.nbt.Tag tag : foreign) { - values.add(toNativeBinary(tag)); - } - - return values.build(); - } - - /** - * Converts a WorldEdit-native NBT structure to a NMS structure. - * - * @param foreign structure to convert - * @return non-native structure - */ - @Override - public net.minecraft.nbt.Tag fromNativeBinary(BinaryTag foreign) { - if (foreign == null) { - return null; - } - if (foreign instanceof CompoundBinaryTag) { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - for (String key : ((CompoundBinaryTag) foreign).keySet()) { - tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); - } - return tag; - } else if (foreign instanceof ByteBinaryTag) { - return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); - } else if (foreign instanceof ByteArrayBinaryTag) { - return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); - } else if (foreign instanceof DoubleBinaryTag) { - return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); - } else if (foreign instanceof FloatBinaryTag) { - return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); - } else if (foreign instanceof IntBinaryTag) { - return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); - } else if (foreign instanceof IntArrayBinaryTag) { - return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); - } else if (foreign instanceof LongArrayBinaryTag) { - return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); - } else if (foreign instanceof ListBinaryTag foreignList) { - net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); - for (BinaryTag t : foreignList) { - tag.add(fromNativeBinary(t)); - } - return tag; - } else if (foreign instanceof LongBinaryTag) { - return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); - } else if (foreign instanceof ShortBinaryTag) { - return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); - } else if (foreign instanceof StringBinaryTag) { - return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); - } else if (foreign instanceof EndBinaryTag) { - return net.minecraft.nbt.EndTag.INSTANCE; - } else { - throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); - } - } - //FAWE end - - @Override - public boolean supportsWatchdog() { - return watchdog != null; - } - - @Override - public void tickWatchdog() { - watchdog.tick(); - } - - private class SpigotWatchdog implements Watchdog { - - private final Field instanceField; - private final Field lastTickField; - - SpigotWatchdog() throws NoSuchFieldException { - Field instanceField = WatchdogThread.class.getDeclaredField("instance"); - instanceField.setAccessible(true); - this.instanceField = instanceField; - - Field lastTickField = WatchdogThread.class.getDeclaredField("lastTick"); - lastTickField.setAccessible(true); - this.lastTickField = lastTickField; - } - - @Override - public void tick() { - try { - WatchdogThread instance = (WatchdogThread) this.instanceField.get(null); - if ((long) lastTickField.get(instance) != 0) { - WatchdogThread.tick(); - } - } catch (IllegalAccessException e) { - LOGGER.log(Level.WARNING, "Failed to tick watchdog", e); - } - } - - } - - private static class MojangWatchdog implements Watchdog { - - private final DedicatedServer server; - private final Field tickField; - - MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { - this.server = server; - Field tickField = MinecraftServer.class.getDeclaredField( - Refraction.pickName("nextTickTime", "ao") - ); - tickField.setAccessible(true); - this.tickField = tickField; - } - - @Override - public void tick() { - try { - tickField.set(server, Util.getMillis()); - } catch (IllegalAccessException ignored) { - } - } - - } - - private static class NoOpWorldLoadListener implements ChunkProgressListener { - - @Override - public void updateSpawnPos(ChunkPos spawnPos) { - } - - @Override - public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) { - } - - @Override - public void start() { - } - - @Override - public void stop() { - } - - @Override - public void setChunkRadius(int radius) { - } - - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightDataConverters.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightDataConverters.java deleted file mode 100644 index 6678bdc52..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightDataConverters.java +++ /dev/null @@ -1,2961 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe; - -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.schemas.Schema; -import com.mojang.serialization.Dynamic; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import net.minecraft.core.Direction; -import net.minecraft.nbt.NbtOps; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.network.chat.TextComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.GsonHelper; -import net.minecraft.util.StringUtil; -import net.minecraft.util.datafix.DataFixers; -import net.minecraft.util.datafix.fixes.References; -import net.minecraft.world.item.DyeColor; -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({"rawtypes", "unchecked"}) -class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { - - //FAWE start - BinaryTag - @SuppressWarnings("unchecked") - @Override - public T fixUp(FixType type, T original, int srcVer) { - if (type == FixTypes.CHUNK) { - return (T) fixChunk((CompoundBinaryTag) original, srcVer); - } else if (type == FixTypes.BLOCK_ENTITY) { - return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); - } else if (type == FixTypes.ENTITY) { - return (T) fixEntity((CompoundBinaryTag) 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 CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); - } - - private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); - } - - private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); - } - //FAWE end - - 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( - References.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.contains("Properties", 10)) { - sb.append('['); - net.minecraft.nbt.CompoundTag props = tagCompound.getCompound("Properties"); - sb.append(props - .getAllKeys() - .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, References.BIOME); - } - - private String fixItemType(String key, int srcVer) { - return fixName(key, srcVer, References.ITEM_NAME); - } - - private static String fixName(String key, int srcVer, TypeReference type) { - return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, net.minecraft.nbt.StringTag.valueOf(key)), srcVer, DATA_VERSION) - .getValue().getAsString(); - } - - private final PaperweightAdapter adapter; - - private static final NbtOps OPS_NBT = NbtOps.INSTANCE; - private static final int LEGACY_VERSION = 1343; - private static int DATA_VERSION; - static PaperweightDataConverters 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(References.LEVEL), - PLAYER(References.PLAYER), - CHUNK(References.CHUNK), - BLOCK_ENTITY(References.BLOCK_ENTITY), - ENTITY(References.ENTITY), - ITEM_INSTANCE(References.ITEM_STACK), - OPTIONS(References.OPTIONS), - STRUCTURE(References.STRUCTURE); - - private final TypeReference type; - - LegacyType(TypeReference type) { - this.type = type; - DFU_TO_LEGACY.put(type.typeName(), this); - } - - public TypeReference getDFUType() { - return type; - } - } - - PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { - super(dataVersion); - DATA_VERSION = dataVersion; - INSTANCE = this; - this.adapter = adapter; - registerConverters(); - registerInspectors(); - } - - - // Called after fixers are built and ready for FIXING - @Override - public DataFixer build(final Executor executor) { - return this.fixer = new WrappedDataFixer(DataFixers.getDataFixer()); - } - - @SuppressWarnings("unchecked") - 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 = PaperweightDataConverters.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 = PaperweightDataConverters.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.contains("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 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, - 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.contains(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.contains(key, 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound.getList(key, 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - nbttaglist.set(j, convert(LegacyType.ITEM_INSTANCE, nbttaglist.getCompound(j), sourceVer, targetVer)); - } - } - - } - - private static class DataConverterEquipment implements DataConverter { - - DataConverterEquipment() { - } - - public int getDataVersion() { - return 100; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("Equipment", 10); - net.minecraft.nbt.ListTag nbttaglist1; - - if (!nbttaglist.isEmpty() && !cmp.contains("HandItems", 10)) { - nbttaglist1 = new net.minecraft.nbt.ListTag(); - nbttaglist1.add(nbttaglist.get(0)); - nbttaglist1.add(new net.minecraft.nbt.CompoundTag()); - cmp.put("HandItems", nbttaglist1); - } - - if (nbttaglist.size() > 1 && !cmp.contains("ArmorItem", 10)) { - nbttaglist1 = new net.minecraft.nbt.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.contains("DropChances", 9)) { - nbttaglist1 = cmp.getList("DropChances", 5); - net.minecraft.nbt.ListTag nbttaglist2; - - if (!cmp.contains("HandDropChances", 10)) { - nbttaglist2 = new net.minecraft.nbt.ListTag(); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(0))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(0.0F)); - cmp.put("HandDropChances", nbttaglist2); - } - - if (!cmp.contains("ArmorDropChances", 10)) { - nbttaglist2 = new net.minecraft.nbt.ListTag(); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(1))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(2))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(3))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(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); - } - } - - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (!cmp.contains("tag", 10)) { - return cmp; - } else { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("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.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(PaperweightDataConverters.class); - - DataInspectorEntity() { - } - - 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.contains("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; - - 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (this.key.equals(new ResourceLocation(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) { - PaperweightDataConverters.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) { - PaperweightDataConverters.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.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"; - // Paper start - materials[409] = "minecraft:prismarine_shard"; - materials[410] = "minecraft:prismarine_crystals"; - materials[411] = "minecraft:rabbit"; - materials[412] = "minecraft:cooked_rabbit"; - materials[413] = "minecraft:rabbit_stew"; - materials[414] = "minecraft:rabbit_foot"; - materials[415] = "minecraft:rabbit_hide"; - materials[416] = "minecraft:armor_stand"; - materials[423] = "minecraft:mutton"; - materials[424] = "minecraft:cooked_mutton"; - materials[425] = "minecraft:banner"; - materials[426] = "minecraft:end_crystal"; - materials[427] = "minecraft:spruce_door"; - materials[428] = "minecraft:birch_door"; - materials[429] = "minecraft:jungle_door"; - materials[430] = "minecraft:acacia_door"; - materials[431] = "minecraft:dark_oak_door"; - materials[432] = "minecraft:chorus_fruit"; - materials[433] = "minecraft:chorus_fruit_popped"; - materials[434] = "minecraft:beetroot"; - materials[435] = "minecraft:beetroot_seeds"; - materials[436] = "minecraft:beetroot_soup"; - materials[437] = "minecraft:dragon_breath"; - materials[438] = "minecraft:splash_potion"; - materials[439] = "minecraft:spectral_arrow"; - materials[440] = "minecraft:tipped_arrow"; - materials[441] = "minecraft:lingering_potion"; - materials[442] = "minecraft:shield"; - materials[443] = "minecraft:elytra"; - materials[444] = "minecraft:spruce_boat"; - materials[445] = "minecraft:birch_boat"; - materials[446] = "minecraft:jungle_boat"; - materials[447] = "minecraft:acacia_boat"; - materials[448] = "minecraft:dark_oak_boat"; - materials[449] = "minecraft:totem_of_undying"; - materials[450] = "minecraft:shulker_shell"; - materials[452] = "minecraft:iron_nugget"; - materials[453] = "minecraft:knowledge_book"; - // Paper end - } - } - - 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.contains("tag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("BlockEntityTag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); - - if (nbttagcompound2.contains("Base", 99)) { - cmp.putShort("Damage", (short) (nbttagcompound2.getShort("Base") & 15)); - if (nbttagcompound1.contains("display", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound3 = nbttagcompound1.getCompound("display"); - - if (nbttagcompound3.contains("Lore", 9)) { - net.minecraft.nbt.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.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 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.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( - "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.contains("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.contains("SpawnPotentials", 9)) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); - - for (int i = 0; i < nbttaglist.size(); ++i) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist.getCompound(i); - - if (nbttagcompound2.contains("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.contains("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.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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("EntityHorse".equals(cmp.getString("id")) && !cmp.contains("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.contains("Facing", 99)) { - Direction enumdirection; - - if (cmp.contains("Direction", 99)) { - enumdirection = Direction.from2DDataValue(cmp.getByte("Direction")); - cmp.putInt("TileX", cmp.getInt("TileX") + enumdirection.getStepX()); - cmp.putInt("TileY", cmp.getInt("TileY") + enumdirection.getStepY()); - cmp.putInt("TileZ", cmp.getInt("TileZ") + enumdirection.getStepZ()); - cmp.remove("Direction"); - if (flag1 && cmp.contains("ItemRotation", 99)) { - cmp.putByte("ItemRotation", (byte) (cmp.getByte("ItemRotation") * 2)); - } - } else { - enumdirection = Direction.from2DDataValue(cmp.getByte("Dir")); - cmp.remove("Dir"); - } - - cmp.putByte("Facing", (byte) enumdirection.get2DDataValue()); - } - - 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) { - net.minecraft.nbt.ListTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - while (cmp.contains("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) { - net.minecraft.nbt.ListTag nbttaglist = new net.minecraft.nbt.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.contains("pages", 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("pages", 8); - - for (int i = 0; i < nbttaglist.size(); ++i) { - String s = nbttaglist.getString(i); - Component object = null; - - if (!"null".equals(s) && !StringUtil.isNullOrEmpty(s)) { - if ((s.charAt(0) != 34 || s.charAt(s.length() - 1) != 34) && (s.charAt(0) != 123 || s.charAt(s.length() - 1) != 125)) { - object = new TextComponent(s); - } else { - try { - object = GsonHelper.fromJson(DataConverterSignText.a, s, Component.class, true); - if (object == null) { - object = new TextComponent(""); - } - } catch (JsonParseException jsonparseexception) { - ; - } - - if (object == null) { - try { - object = Component.Serializer.fromJson(s); - } catch (JsonParseException jsonparseexception1) { - ; - } - } - - if (object == null) { - try { - object = Component.Serializer.fromJsonLenient(s); - } catch (JsonParseException jsonparseexception2) { - ; - } - } - - if (object == null) { - object = new TextComponent(s); - } - } - } else { - object = new TextComponent(""); - } - - nbttaglist.set(i, net.minecraft.nbt.StringTag.valueOf(Component.Serializer.toJson(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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 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 0: - default: - break; - - 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"); - } - - 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 0: - default: - cmp.putString("id", "Horse"); - break; - - 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"); - } - - 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.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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:shulker_box".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("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.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 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(PaperweightDataConverters.class); - - DataConverterBedBlock() { - } - - public int getDataVersion() { - return 1125; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - try { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); - int i = nbttagcompound1.getInt("xPos"); - int j = nbttagcompound1.getInt("zPos"); - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("TileEntities", 10); - net.minecraft.nbt.ListTag nbttaglist1 = nbttagcompound1.getList("Sections", 10); - - for (int k = 0; k < nbttaglist1.size(); ++k) { - net.minecraft.nbt.CompoundTag 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; - net.minecraft.nbt.CompoundTag nbttagcompound3 = new net.minecraft.nbt.CompoundTag(); - - nbttagcompound3.putString("id", "bed"); - nbttagcompound3.putInt("x", i1 + (i << 4)); - nbttagcompound3.putInt("y", j1 + (b0 << 4)); - nbttagcompound3.putInt("z", k1 + (j << 4)); - nbttaglist.add(nbttagcompound3); - } - } - } - } catch (Exception exception) { - DataConverterBedBlock.a.warn("Unable to datafix Bed blocks, level format may be missing tags."); - } - - return cmp; - } - - } - - private static class DataConverterBedItem implements DataConverter { - - DataConverterBedItem() { - } - - public int getDataVersion() { - return 1125; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:bed".equals(cmp.getString("id")) && cmp.getShort("Damage") == 0) { - cmp.putShort("Damage", (short) DyeColor.RED.getId()); - } - - return cmp; - } - - } - - private static class DataConverterSignText implements DataConverter { - - public static final Gson a = new GsonBuilder().registerTypeAdapter(Component.class, new JsonDeserializer() { - MutableComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws - JsonParseException { - if (jsonelement.isJsonPrimitive()) { - return new TextComponent(jsonelement.getAsString()); - } else if (jsonelement.isJsonArray()) { - JsonArray jsonarray = jsonelement.getAsJsonArray(); - MutableComponent ichatbasecomponent = null; - Iterator iterator = jsonarray.iterator(); - - while (iterator.hasNext()) { - JsonElement jsonelement1 = (JsonElement) iterator.next(); - MutableComponent ichatbasecomponent1 = this.a( - jsonelement1, - jsonelement1.getClass(), - jsondeserializationcontext - ); - - if (ichatbasecomponent == null) { - ichatbasecomponent = ichatbasecomponent1; - } else { - ichatbasecomponent.append(ichatbasecomponent1); - } - } - - return ichatbasecomponent; - } 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); - Component object = null; - - if (!"null".equals(s1) && !StringUtil.isNullOrEmpty(s1)) { - if ((s1.charAt(0) != 34 || s1.charAt(s1.length() - 1) != 34) && (s1.charAt(0) != 123 || s1.charAt(s1.length() - 1) != 125)) { - object = new TextComponent(s1); - } else { - try { - object = GsonHelper.fromJson(DataConverterSignText.a, s1, Component.class, true); - if (object == null) { - object = new TextComponent(""); - } - } catch (JsonParseException jsonparseexception) { - ; - } - - if (object == null) { - try { - object = Component.Serializer.fromJson(s1); - } catch (JsonParseException jsonparseexception1) { - ; - } - } - - if (object == null) { - try { - object = Component.Serializer.fromJsonLenient(s1); - } catch (JsonParseException jsonparseexception2) { - ; - } - } - - if (object == null) { - object = new TextComponent(s1); - } - } - } else { - object = new TextComponent(""); - } - - nbttagcompound.putString(s, Component.Serializer.toJson(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.contains("RootVehicle", 10)) { - net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - net.minecraft.nbt.ListTag nbttaglist; - int j; - net.minecraft.nbt.CompoundTag nbttagcompound1; - - if (cmp.contains("entities", 9)) { - nbttaglist = cmp.getList("entities", 10); - - for (j = 0; j < nbttaglist.size(); ++j) { - nbttagcompound1 = (net.minecraft.nbt.CompoundTag) 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 = (net.minecraft.nbt.CompoundTag) 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (cmp.contains("Level", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); - net.minecraft.nbt.ListTag 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, - (net.minecraft.nbt.CompoundTag) 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, - (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.contains("Passengers", 9)) { - net.minecraft.nbt.ListTag 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 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.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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (entityVillager.equals(new ResourceLocation(cmp.getString("id"))) && cmp.contains("Offers", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Offers"); - - if (nbttagcompound1.contains("Recipes", 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("Recipes", 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (tileEntityMobSpawner.equals(new ResourceLocation(cmp.getString("id")))) { - if (cmp.contains("SpawnPotentials", 9)) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightFakePlayer.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightFakePlayer.java deleted file mode 100644 index 9f081b05e..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightFakePlayer.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe; - -import com.mojang.authlib.GameProfile; -import net.minecraft.network.chat.ChatType; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ServerboundClientInformationPacket; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.stats.Stat; -import net.minecraft.world.MenuProvider; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.block.entity.SignBlockEntity; -import net.minecraft.world.phys.Vec3; -import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; - -import java.util.OptionalInt; -import java.util.UUID; - -class PaperweightFakePlayer extends ServerPlayer { - - private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile( - UUID.nameUUIDFromBytes("worldedit".getBytes()), - "[WorldEdit]" - ); - private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D); - - PaperweightFakePlayer(ServerLevel world) { - super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE); - } - - @Override - public Vec3 position() { - return ORIGIN; - } - - @Override - public void tick() { - } - - @Override - public void die(DamageSource damagesource) { - } - - @Override - public Entity changeDimension(ServerLevel worldserver, TeleportCause cause) { - return this; - } - - @Override - public OptionalInt openMenu(MenuProvider factory) { - return OptionalInt.empty(); - } - - @Override - public void updateOptions(ServerboundClientInformationPacket packet) { - } - - @Override - public void displayClientMessage(Component message, boolean actionBar) { - } - - @Override - public void sendMessage(Component message, ChatType type, UUID sender) { - } - - @Override - public void awardStat(Stat stat, int amount) { - } - - @Override - public void awardStat(Stat stat) { - } - - @Override - public boolean isInvulnerableTo(DamageSource damageSource) { - return true; - } - - @Override - public void openTextEdit(SignBlockEntity sign) { - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightWorldNativeAccess.java deleted file mode 100644 index 701e40b12..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightWorldNativeAccess.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe; - -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.world.block.BlockState; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.chunk.LevelChunk; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; -import org.bukkit.event.block.BlockPhysicsEvent; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.util.Objects; - -public class PaperweightWorldNativeAccess implements - WorldNativeAccess { - - private static final int UPDATE = 1; - private static final int NOTIFY = 2; - - private final PaperweightAdapter adapter; - private final WeakReference world; - private SideEffectSet sideEffectSet; - - public PaperweightWorldNativeAccess(PaperweightAdapter adapter, WeakReference world) { - this.adapter = adapter; - this.world = world; - } - - private ServerLevel getWorld() { - return Objects.requireNonNull(world.get(), "The reference to the world was lost"); - } - - @Override - public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { - this.sideEffectSet = sideEffectSet; - } - - @Override - public LevelChunk getChunk(int x, int z) { - return getWorld().getChunk(x, z); - } - - @Override - public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) { - int stateId = BlockStateIdAccess.getBlockStateId(state); - return BlockStateIdAccess.isValidInternalId(stateId) - ? Block.stateById(stateId) - : ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk chunk, BlockPos position) { - return chunk.getBlockState(position); - } - - @Nullable - @Override - public net.minecraft.world.level.block.state.BlockState setBlockState( - LevelChunk chunk, - BlockPos position, - net.minecraft.world.level.block.state.BlockState state - ) { - return chunk.setType(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE)); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition( - net.minecraft.world.level.block.state.BlockState block, - BlockPos position - ) { - return Block.updateFromNeighbourShapes(block, getWorld(), position); - } - - @Override - public BlockPos getPosition(int x, int y, int z) { - return new BlockPos(x, y, z); - } - - @Override - public void updateLightingForBlock(BlockPos position) { - getWorld().getChunkSource().getLightEngine().checkBlock(position); - } - - @Override - public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { - return false; - } - - @Override - public void notifyBlockUpdate( - LevelChunk chunk, - BlockPos position, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { - getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY); - } - } - - @Override - public boolean isChunkTicking(LevelChunk chunk) { - return chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); - } - - @Override - public void markBlockChanged(LevelChunk chunk, BlockPos position) { - if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { - getWorld().getChunkSource().blockChanged(position); - } - } - - @Override - public void notifyNeighbors( - BlockPos pos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - ServerLevel world = getWorld(); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - world.updateNeighborsAt(pos, oldState.getBlock()); - } else { - // When we don't want events, manually run the physics without them. - Block block = oldState.getBlock(); - fireNeighborChanged(pos, world, block, pos.west()); - fireNeighborChanged(pos, world, block, pos.east()); - fireNeighborChanged(pos, world, block, pos.below()); - fireNeighborChanged(pos, world, block, pos.above()); - fireNeighborChanged(pos, world, block, pos.north()); - fireNeighborChanged(pos, world, block, pos.south()); - } - if (newState.hasAnalogOutputSignal()) { - world.updateNeighbourForOutputSignal(pos, newState.getBlock()); - } - } - - private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { - world.getBlockState(neighborPos).neighborChanged(world, neighborPos, block, pos, false); - } - - @Override - public void updateNeighbors( - BlockPos pos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState, - int recursionLimit - ) { - ServerLevel world = getWorld(); - // a == updateNeighbors - // b == updateDiagonalNeighbors - oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - CraftWorld craftWorld = world.getWorld(); - BlockPhysicsEvent event = new BlockPhysicsEvent( - craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), - CraftBlockData.fromData(newState) - ); - world.getCraftServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - } - newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit); - newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); - } - - @Override - public void onBlockStateChange( - BlockPos pos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - getWorld().onBlockStateChange(pos, oldState, newState); - } - - @Override - public void flush() { - - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightBlockMaterial.java deleted file mode 100644 index aac664459..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightBlockMaterial.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; - -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.util.ReflectionUtil; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.world.registry.BlockMaterial; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.EmptyBlockGetter; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.EntityBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.Material; -import net.minecraft.world.level.material.PushReaction; -import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; - -public class PaperweightBlockMaterial implements BlockMaterial { - - private final Block block; - private final BlockState blockState; - private final Material material; - private final boolean isTranslucent; - private final CraftBlockData craftBlockData; - private final org.bukkit.Material craftMaterial; - private final int opacity; - private final CompoundTag tile; - - public PaperweightBlockMaterial(Block block) { - this(block, block.defaultBlockState()); - } - - public PaperweightBlockMaterial(Block block, BlockState blockState) { - this.block = block; - this.blockState = blockState; - this.material = blockState.getMaterial(); - this.craftBlockData = CraftBlockData.fromData(blockState); - this.craftMaterial = craftBlockData.getMaterial(); - BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, Refraction.pickName( - "properties", "aP")); - this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo, - Refraction.pickName("canOcclude", "n") - ); - opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); - BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity( - BlockPos.ZERO, - blockState - ); - tile = tileEntity == null - ? null - : new PaperweightLazyCompoundTag(Suppliers.memoize(() -> tileEntity.save(new net.minecraft.nbt.CompoundTag()))); - } - - public Block getBlock() { - return block; - } - - public BlockState getState() { - return blockState; - } - - public CraftBlockData getCraftBlockData() { - return craftBlockData; - } - - public Material getMaterial() { - return material; - } - - @Override - public boolean isAir() { - return blockState.isAir(); - } - - @Override - public boolean isFullCube() { - return craftMaterial.isOccluding(); - } - - @Override - public boolean isOpaque() { - return material.isSolidBlocking(); - } - - @Override - public boolean isPowerSource() { - return blockState.isSignalSource(); - } - - @Override - public boolean isLiquid() { - return material.isLiquid(); - } - - @Override - public boolean isSolid() { - return material.isSolid(); - } - - @Override - public float getHardness() { - return craftBlockData.getState().destroySpeed; - } - - @Override - public float getResistance() { - return block.getExplosionResistance(); - } - - @Override - public float getSlipperiness() { - return block.getFriction(); - } - - @Override - public int getLightValue() { - return blockState.getLightEmission(); - } - - @Override - public int getLightOpacity() { - return opacity; - } - - @Override - public boolean isFragileWhenPushed() { - return material.getPushReaction() == PushReaction.DESTROY; - } - - @Override - public boolean isUnpushable() { - return material.getPushReaction() == PushReaction.BLOCK; - } - - @Override - public boolean isTicksRandomly() { - return block.isRandomlyTicking(blockState); - } - - @Override - public boolean isMovementBlocker() { - return material.isSolid(); - } - - @Override - public boolean isBurnable() { - return material.isFlammable(); - } - - @Override - public boolean isToolRequired() { - // Removed in 1.16.1, this is not present in higher versions - return false; - } - - @Override - public boolean isReplacedDuringPlacement() { - return material.isReplaceable(); - } - - @Override - public boolean isTranslucent() { - return isTranslucent; - } - - @Override - public boolean hasContainer() { - return block instanceof EntityBlock; - } - - @Override - public boolean isTile() { - return block instanceof EntityBlock; - } - - @Override - public CompoundTag getDefaultTile() { - return tile; - } - - @Override - public int getMapColor() { - // rgb field - return material.getColor().col; - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweAdapter.java deleted file mode 100644 index ad6e6ae80..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweAdapter.java +++ /dev/null @@ -1,671 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; - -import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; -import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.entity.LazyBaseEntity; -import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IBatchProcessor; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; -import com.fastasyncworldedit.core.util.NbtUtils; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.blocks.TileEntityBlock; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.ext.fawe.PaperweightAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.regen.PaperweightRegen; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; -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.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; -import com.sk89q.worldedit.world.RegenOptions; -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.block.BlockType; -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.item.ItemType; -import com.sk89q.worldedit.world.registry.BlockMaterial; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Registry; -import net.minecraft.core.WritableRegistry; -import net.minecraft.nbt.IntTag; -import net.minecraft.network.protocol.game.ClientboundLevelChunkPacket; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.util.StringRepresentable; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.DirectionProperty; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.World; -import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_17_R1.CraftServer; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_17_R1.util.CraftNamespacedKey; -import org.bukkit.entity.Player; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.OptionalInt; -import java.util.Set; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public final class PaperweightFaweAdapter extends FaweAdapter { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private final PaperweightAdapter parent; - // ------------------------------------------------------------------------ - // Code that may break between versions of Minecraft - // ------------------------------------------------------------------------ - private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil(); - private char[] ibdToStateOrdinal = null; - private int[] ordinalToIbdID = null; - private boolean initialised = false; - private Map>> allBlockProperties = null; - - public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { - this.parent = new PaperweightAdapter(); - } - - @Nullable - private static String getEntityId(Entity entity) { - ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType()); - return resourceLocation == null ? null : resourceLocation.toString(); - } - - @Override - public BukkitImplAdapter getParent() { - return parent; - } - - @SuppressWarnings("unchecked") - private synchronized boolean init() { - if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) { - return false; - } - ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size - ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size - for (int i = 0; i < ibdToStateOrdinal.length; i++) { - BlockState blockState = BlockTypesCache.states[i]; - PaperweightBlockMaterial material = (PaperweightBlockMaterial) blockState.getMaterial(); - int id = Block.BLOCK_STATE_REGISTRY.getId(material.getState()); - char ordinal = blockState.getOrdinalChar(); - ibdToStateOrdinal[id] = ordinal; - ordinalToIbdID[ordinal] = id; - } - Map>> properties = new HashMap<>(); - try { - for (Field field : BlockStateProperties.class.getDeclaredFields()) { - Object obj = field.get(null); - if (!(obj instanceof net.minecraft.world.level.block.state.properties.Property state)) { - continue; - } - Property property; - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - property = new BooleanProperty( - state.getName(), - (List) ImmutableList.copyOf(state.getPossibleValues()) - ); - } else if (state instanceof DirectionProperty) { - property = new DirectionalProperty( - state.getName(), - state - .getPossibleValues() - .stream() - .map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase())) - .collect(Collectors.toList()) - ); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - property = new EnumProperty( - state.getName(), - state - .getPossibleValues() - .stream() - .map(e -> ((StringRepresentable) e).getSerializedName()) - .collect(Collectors.toList()) - ); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - property = new IntegerProperty( - state.getName(), - (List) ImmutableList.copyOf(state.getPossibleValues()) - ); - } else { - throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state - .getClass() - .getSimpleName()); - } - properties.compute(property.getName().toLowerCase(Locale.ROOT), (k, v) -> { - if (v == null) { - v = new ArrayList<>(Collections.singletonList(property)); - } else { - v.add(property); - } - return v; - }); - } - } catch (IllegalAccessException e) { - e.printStackTrace(); - } finally { - allBlockProperties = ImmutableMap.copyOf(properties); - } - initialised = true; - return true; - } - - @Override - public BlockMaterial getMaterial(BlockType blockType) { - Block block = getBlock(blockType); - return new PaperweightBlockMaterial(block); - } - - @Override - public synchronized BlockMaterial getMaterial(BlockState state) { - net.minecraft.world.level.block.state.BlockState blockState = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState(); - return new PaperweightBlockMaterial(blockState.getBlock(), blockState); - } - - public Block getBlock(BlockType blockType) { - return Registry.BLOCK.get(new ResourceLocation(blockType.getNamespace(), blockType.getResource())); - } - - @Deprecated - @Override - public BlockState getBlock(Location location) { - Preconditions.checkNotNull(location); - - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - final ServerLevel handle = getServerLevel(location.getWorld()); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - BlockState state = adapt(blockData); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - return state; - } - - @Override - public BaseBlock getFullBlock(final Location location) { - Preconditions.checkNotNull(location); - - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = getServerLevel(location.getWorld()); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - BlockState state = adapt(blockData); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - if (state.getBlockType().getMaterial().hasContainer()) { - - // Read the NBT data - BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); - if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = blockEntity.save(new net.minecraft.nbt.CompoundTag()); - return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); - } - } - - return state.toBaseBlock(); - } - - @Override - public Set getSupportedSideEffects() { - return SideEffectSet.defaults().getSideEffectsToApply(); - } - - @SuppressWarnings("rawtypes") - public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) { - CraftChunk craftChunk = (CraftChunk) chunk; - LevelChunk levelChunk = craftChunk.getHandle(); - Level level = levelChunk.getLevel(); - - BlockPos blockPos = new BlockPos(x, y, z); - net.minecraft.world.level.block.state.BlockState blockState = ((PaperweightBlockMaterial) state.getMaterial()).getState(); - LevelChunkSection[] levelChunkSections = levelChunk.getSections(); - int y4 = y >> 4; - LevelChunkSection section = levelChunkSections[y4]; - - net.minecraft.world.level.block.state.BlockState existing; - if (section == null) { - existing = ((PaperweightBlockMaterial) BlockTypes.AIR.getDefaultState().getMaterial()).getState(); - } else { - existing = section.getBlockState(x & 15, y & 15, z & 15); - } - - levelChunk.removeBlockEntity(blockPos); // Force delete the old tile entity - - CompoundBinaryTag compoundTag = state instanceof BaseBlock ? state.getNbt() : null; - if (compoundTag != null || existing instanceof TileEntityBlock) { - level.setBlock(blockPos, blockState, 0); - // remove tile - if (compoundTag != null) { - // We will assume that the tile entity was created for us, - // though we do not do this on the Forge version - BlockEntity blockEntity = level.getBlockEntity(blockPos); - if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(compoundTag); - tag.put("x", IntTag.valueOf(x)); - tag.put("y", IntTag.valueOf(y)); - tag.put("z", IntTag.valueOf(z)); - blockEntity.load(tag); // readTagIntoTileEntity - load data - } - } - } else { - if (existing == blockState) { - return true; - } - if (section == null) { - if (blockState.isAir()) { - return true; - } - levelChunkSections[y4] = section = new LevelChunkSection(y4 << 4); - } - levelChunk.setBlockState(blockPos, blockState, false); - } - if (update) { - level.getMinecraftWorld().sendBlockUpdated(blockPos, existing, blockState, 0); - } - return true; - } - - @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); - } - - @Override - public BaseEntity getEntity(org.bukkit.entity.Entity entity) { - Preconditions.checkNotNull(entity); - - CraftEntity craftEntity = ((CraftEntity) entity); - Entity mcEntity = craftEntity.getHandle(); - - String id = getEntityId(mcEntity); - - if (id != null) { - EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); - Supplier saveTag = () -> { - final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(mcEntity, minecraftTag); - //add Id for AbstractChangeSet to work - final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); - final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); - tags.put("Id", StringBinaryTag.of(id)); - return CompoundBinaryTag.from(tags); - }; - return new LazyBaseEntity(type, saveTag); - } else { - return null; - } - } - - @Override - public Component getRichBlockName(BlockType blockType) { - return parent.getRichBlockName(blockType); - } - - @Override - public Component getRichItemName(ItemType itemType) { - return parent.getRichItemName(itemType); - } - - @Override - public Component getRichItemName(BaseItemStack itemStack) { - return parent.getRichItemName(itemStack); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockState state) { - PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); - net.minecraft.world.level.block.state.BlockState mcState = material.getCraftBlockData().getState(); - return OptionalInt.of(Block.BLOCK_STATE_REGISTRY.getId(mcState)); - } - - @Override - public BlockState adapt(BlockData blockData) { - CraftBlockData cbd = ((CraftBlockData) blockData); - net.minecraft.world.level.block.state.BlockState ibd = cbd.getState(); - return adapt(ibd); - } - - public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) { - return BlockTypesCache.states[adaptToChar(blockState)]; - } - - public char adaptToChar(net.minecraft.world.level.block.state.BlockState blockState) { - int id = Block.BLOCK_STATE_REGISTRY.getId(blockState); - if (initialised) { - return ibdToStateOrdinal[id]; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - try { - init(); - return ibdToStateOrdinal[id]; - } catch (ArrayIndexOutOfBoundsException e1) { - LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!", - blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1 - ); - return BlockTypesCache.ReservedIDs.AIR; - } - } - } - - public char ibdIDToOrdinal(int id) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - init(); - return ibdToStateOrdinal[id]; - } - } - - @Override - public char[] getIbdToStateOrdinal() { - if (initialised) { - return ibdToStateOrdinal; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal; - } - init(); - return ibdToStateOrdinal; - } - } - - public int ordinalToIbdID(char ordinal) { - if (initialised) { - return ordinalToIbdID[ordinal]; - } - synchronized (this) { - if (initialised) { - return ordinalToIbdID[ordinal]; - } - init(); - return ordinalToIbdID[ordinal]; - } - } - - @Override - public int[] getOrdinalToIbdID() { - if (initialised) { - return ordinalToIbdID; - } - synchronized (this) { - if (initialised) { - return ordinalToIbdID; - } - init(); - return ordinalToIbdID; - } - } - - @Override - public > BlockData adapt(B state) { - PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); - return material.getCraftBlockData(); - } - - @Override - public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { - ServerLevel nmsWorld = getServerLevel(world); - ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); - if (map != null && map.wasAccessibleSinceLastSave()) { - boolean flag = false; - // PlayerChunk.d players = map.players; - Stream stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag) - */ Stream.empty(); - - ServerPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle(); - stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer) - .forEach(entityPlayer -> { - synchronized (chunkPacket) { - ClientboundLevelChunkPacket nmsPacket = (ClientboundLevelChunkPacket) chunkPacket.getNativePacket(); - if (nmsPacket == null) { - nmsPacket = mapUtil.create(this, chunkPacket); - chunkPacket.setNativePacket(nmsPacket); - } - try { - FaweCache.INSTANCE.CHUNK_FLAG.get().set(true); - entityPlayer.connection.send(nmsPacket); - } finally { - FaweCache.INSTANCE.CHUNK_FLAG.get().set(false); - } - } - }); - } - } - - @Override - public Map> getProperties(BlockType blockType) { - return getParent().getProperties(blockType); - } - - @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) { - int internalId = BlockStateIdAccess.getBlockStateId(blockState); - net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); - return blockState1.hasPostProcess( - getServerLevel(world), - new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) - ); - } - - @Override - public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { - ItemStack stack = new ItemStack( - Registry.ITEM.get(ResourceLocation.tryParse(baseItemStack.getType().getId())), - baseItemStack.getAmount() - ); - stack.setTag(((net.minecraft.nbt.CompoundTag) fromNativeBinary(baseItemStack.getNbt()))); - return CraftItemStack.asCraftMirror(stack); - } - - @Override - protected void preCaptureStates(final ServerLevel serverLevel) { - serverLevel.captureTreeGeneration = true; - serverLevel.captureBlockStates = true; - } - - @Override - protected List getCapturedBlockStatesCopy(final ServerLevel serverLevel) { - return new ArrayList<>(serverLevel.capturedBlockStates.values()); - } - - @Override - protected void postCaptureBlockStates(final ServerLevel serverLevel) { - serverLevel.captureBlockStates = false; - serverLevel.captureTreeGeneration = false; - serverLevel.capturedBlockStates.clear(); - } - - @Override - protected ServerLevel getServerLevel(final World world) { - return ((CraftWorld) world).getHandle(); - } - - @Override - public List getEntities(org.bukkit.World world) { - // Quickly add each entity to a list copy. - List mcEntities = new ArrayList<>(); - getServerLevel(world).entityManager.getEntityGetter().getAll().forEach(mcEntities::add); - - List list = new ArrayList<>(); - mcEntities.forEach((mcEnt) -> { - org.bukkit.entity.Entity bukkitEntity = mcEnt.getBukkitEntity(); - if (bukkitEntity.isValid()) { - list.add(bukkitEntity); - } - - }); - return list; - } - - @Override - public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { - final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); - final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); - weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); - return weStack; - } - - @Override - public Tag toNative(net.minecraft.nbt.Tag foreign) { - return parent.toNative(foreign); - } - - @Override - public net.minecraft.nbt.Tag fromNative(Tag foreign) { - if (foreign instanceof PaperweightLazyCompoundTag) { - return ((PaperweightLazyCompoundTag) foreign).get(); - } - return parent.fromNative(foreign); - } - - @Override - public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { - return new PaperweightRegen(bukkitWorld, region, target, options).regenerate(); - } - - @Override - public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { - return new PaperweightGetBlocks(world, chunkX, chunkZ); - } - - @Override - public int getInternalBiomeId(BiomeType biomeType) { - final Registry registry = MinecraftServer - .getServer() - .registryAccess() - .ownedRegistryOrThrow(Registry.BIOME_REGISTRY); - ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.getId()); - Biome biome = registry.get(resourceLocation); - return registry.getId(biome); - } - - @Override - public Iterable getRegisteredBiomes() { - WritableRegistry biomeRegistry = ((CraftServer) Bukkit.getServer()) - .getServer() - .registryAccess() - .ownedRegistryOrThrow( - Registry.BIOME_REGISTRY); - List keys = biomeRegistry.stream() - .map(biomeRegistry::getKey).filter(Objects::nonNull).toList(); - List namespacedKeys = new ArrayList<>(); - for (ResourceLocation key : keys) { - try { - namespacedKeys.add(CraftNamespacedKey.fromMinecraft(key)); - } catch (IllegalArgumentException e) { - LOGGER.error("Error converting biome key {}", key.toString(), e); - } - } - return namespacedKeys; - } - - @Override - public RelighterFactory getRelighterFactory() { - try { - Class.forName("ca.spottedleaf.starlight.light.StarLightEngine"); - if (PaperweightStarlightRelighter.isUsable()) { - return new PaperweightStarlightRelighterFactory(); - } - } catch (ThreadDeath td) { - throw td; - } catch (Throwable ignored) { - - } - return new NMSRelighterFactory(); - } - - @Override - public Map>> getAllProperties() { - if (initialised) { - return allBlockProperties; - } - synchronized (this) { - if (initialised) { - return allBlockProperties; - } - init(); - return allBlockProperties; - } - } - - @Override - public IBatchProcessor getTickingPostProcessor() { - return new PaperweightPostProcessor(); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweWorldNativeAccess.java deleted file mode 100644 index 282a6b505..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweWorldNativeAccess.java +++ /dev/null @@ -1,286 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; - -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.math.IntPair; -import com.fastasyncworldedit.core.util.TaskManager; -import com.fastasyncworldedit.core.util.task.RunnableVal; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.world.block.BlockState; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.LevelChunk; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; -import org.bukkit.event.block.BlockPhysicsEvent; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.util.Collections; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; - -public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess { - - private static final int UPDATE = 1; - private static final int NOTIFY = 2; - private static final Direction[] NEIGHBOUR_ORDER = { - Direction.EAST, - Direction.WEST, - Direction.DOWN, - Direction.UP, - Direction.NORTH, - Direction.SOUTH - }; - private final PaperweightFaweAdapter paperweightFaweAdapter; - private final WeakReference level; - private final AtomicInteger lastTick; - private final Set cachedChanges = new HashSet<>(); - private final Set cachedChunksToSend = new HashSet<>(); - private SideEffectSet sideEffectSet; - - public PaperweightFaweWorldNativeAccess(PaperweightFaweAdapter paperweightFaweAdapter, WeakReference level) { - this.paperweightFaweAdapter = paperweightFaweAdapter; - this.level = level; - // Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging. - // - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway. - this.lastTick = new AtomicInteger(MinecraftServer.currentTick); - } - - private Level getLevel() { - return Objects.requireNonNull(level.get(), "The reference to the world was lost"); - } - - @Override - public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { - this.sideEffectSet = sideEffectSet; - } - - @Override - public LevelChunk getChunk(int x, int z) { - return getLevel().getChunk(x, z); - } - - @Override - public net.minecraft.world.level.block.state.BlockState toNative(BlockState blockState) { - int stateId = paperweightFaweAdapter.ordinalToIbdID(blockState.getOrdinalChar()); - return BlockStateIdAccess.isValidInternalId(stateId) - ? Block.stateById(stateId) - : ((CraftBlockData) BukkitAdapter.adapt(blockState)).getState(); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk levelChunk, BlockPos blockPos) { - return levelChunk.getBlockState(blockPos); - } - - @Nullable - @Override - public synchronized net.minecraft.world.level.block.state.BlockState setBlockState( - LevelChunk levelChunk, BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState blockState - ) { - int currentTick = MinecraftServer.currentTick; - if (Fawe.isMainThread()) { - return levelChunk.setBlockState(blockPos, blockState, - this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE) - ); - } - // Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( ) - cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState)); - cachedChunksToSend.add(new IntPair(levelChunk.bukkitChunk.getX(), levelChunk.bukkitChunk.getZ())); - boolean nextTick = lastTick.get() > currentTick; - if (nextTick || cachedChanges.size() >= 1024) { - if (nextTick) { - lastTick.set(currentTick); - } - flushAsync(nextTick); - } - return blockState; - } - - @Override - public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition( - net.minecraft.world.level.block.state.BlockState blockState, - BlockPos blockPos - ) { - return Block.updateFromNeighbourShapes(blockState, getLevel(), blockPos); - } - - @Override - public BlockPos getPosition(int x, int y, int z) { - return new BlockPos(x, y, z); - } - - @Override - public void updateLightingForBlock(BlockPos blockPos) { - getLevel().getChunkSource().getLightEngine().checkBlock(blockPos); - } - - @Override - public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) { - // We will assume that the tile entity was created for us, - // though we do not do this on the other versions - BlockEntity blockEntity = getLevel().getBlockEntity(blockPos); - if (blockEntity == null) { - return false; - } - net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeBinary(tag); - blockEntity.load((CompoundTag) nativeTag); - return true; - } - - @Override - public void notifyBlockUpdate( - LevelChunk levelChunk, BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { - getLevel().sendBlockUpdated(blockPos, oldState, newState, UPDATE | NOTIFY); - } - } - - @Override - public boolean isChunkTicking(LevelChunk levelChunk) { - return levelChunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); - } - - @Override - public void markBlockChanged(LevelChunk levelChunk, BlockPos blockPos) { - if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { - ((ServerChunkCache) getLevel().getChunkSource()).blockChanged(blockPos); - } - } - - @Override - public void notifyNeighbors( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - Level level = getLevel(); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - level.blockUpdated(blockPos, oldState.getBlock()); - } else { - // When we don't want events, manually run the physics without them. - // Un-nest neighbour updating - for (Direction direction : NEIGHBOUR_ORDER) { - BlockPos shifted = blockPos.relative(direction); - level.getBlockState(shifted).neighborChanged(level, shifted, oldState.getBlock(), blockPos, false); - } - } - if (newState.hasAnalogOutputSignal()) { - level.updateNeighbourForOutputSignal(blockPos, newState.getBlock()); - } - } - - @Override - public void updateNeighbors( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState, - int recursionLimit - ) { - Level level = getLevel(); - // a == updateNeighbors - // b == updateDiagonalNeighbors - oldState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - CraftWorld craftWorld = level.getWorld(); - if (craftWorld != null) { - BlockPhysicsEvent event = new BlockPhysicsEvent( - craftWorld.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()), - CraftBlockData.fromData(newState) - ); - level.getCraftServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - } - } - newState.triggerEvent(level, blockPos, NOTIFY, recursionLimit); - newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); - } - - @Override - public void onBlockStateChange( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - getLevel().onBlockStateChange(blockPos, oldState, newState); - } - - private synchronized void flushAsync(final boolean sendChunks) { - final Set changes = Set.copyOf(cachedChanges); - cachedChanges.clear(); - final Set toSend; - if (sendChunks) { - toSend = Set.copyOf(cachedChunksToSend); - cachedChunksToSend.clear(); - } else { - toSend = Collections.emptySet(); - } - RunnableVal runnableVal = new RunnableVal<>() { - @Override - public void run(Object value) { - changes.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, - sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) - )); - if (!sendChunks) { - return; - } - for (IntPair chunk : toSend) { - PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); - } - } - }; - TaskManager.taskManager().async(() -> TaskManager.taskManager().sync(runnableVal)); - } - - @Override - public synchronized void flush() { - RunnableVal runnableVal = new RunnableVal<>() { - @Override - public void run(Object value) { - cachedChanges.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, - sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) - )); - for (IntPair chunk : cachedChunksToSend) { - PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); - } - } - }; - if (Fawe.isMainThread()) { - runnableVal.run(); - } else { - TaskManager.taskManager().sync(runnableVal); - } - cachedChanges.clear(); - cachedChunksToSend.clear(); - } - - private record CachedChange( - LevelChunk levelChunk, - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState blockState - ) { - - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java deleted file mode 100644 index 214a39bc6..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java +++ /dev/null @@ -1,1096 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; - -import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; -import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; -import com.fastasyncworldedit.core.math.BitArrayUnstretched; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.fastasyncworldedit.core.queue.implementation.QueueHandler; -import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.collection.AdaptedMap; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.internal.Constants; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import io.papermc.lib.PaperLib; -import io.papermc.paper.event.block.BeaconDeactivatedEvent; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; -import net.minecraft.nbt.IntTag; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.util.BitStorage; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.entity.BeaconBlockEntity; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.ChunkBiomeContainer; -import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.HashMapPalette; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.LinearPalette; -import net.minecraft.world.level.chunk.Palette; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.level.lighting.LevelLightEngine; -import org.apache.logging.log4j.Logger; -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import javax.annotation.Nonnull; -import java.util.AbstractSet; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Future; -import java.util.concurrent.Semaphore; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.function.Function; -import java.util.stream.Collectors; - -public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private static final Function posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); - private static final Function nmsTile2We = - tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize( - () -> tileEntity.save(new net.minecraft.nbt.CompoundTag()))); - private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin - .getInstance() - .getBukkitImplAdapter()); - private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); - private final ReentrantLock callLock = new ReentrantLock(); - private final ServerLevel serverLevel; - private final int chunkX; - private final int chunkZ; - private final int minHeight; - private final int maxHeight; - private final int minSectionPosition; - private final int maxSectionPosition; - private final ConcurrentHashMap copies = new ConcurrentHashMap<>(); - private final Object sendLock = new Object(); - private LevelChunkSection[] sections; - private LevelChunk levelChunk; - private DataLayer[] blockLight; - private DataLayer[] skyLight; - private boolean createCopy = false; - private boolean forceLoadSections = true; - private boolean lightUpdate = false; - private int copyKey = 0; - - public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { - this(((CraftWorld) world).getHandle(), chunkX, chunkZ); - } - - public PaperweightGetBlocks(ServerLevel serverLevel, int chunkX, int chunkZ) { - super(serverLevel.getMinBuildHeight() >> 4, (serverLevel.getMaxBuildHeight() - 1) >> 4); - this.serverLevel = serverLevel; - this.chunkX = chunkX; - this.chunkZ = chunkZ; - this.minHeight = serverLevel.getMinBuildHeight(); - this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. - this.minSectionPosition = minHeight >> 4; - this.maxSectionPosition = maxHeight >> 4; - this.skyLight = new DataLayer[getSectionCount()]; - this.blockLight = new DataLayer[getSectionCount()]; - } - - public int getChunkX() { - return chunkX; - } - - public int getChunkZ() { - return chunkZ; - } - - @Override - public boolean isCreateCopy() { - return createCopy; - } - - @Override - public int setCreateCopy(boolean createCopy) { - if (!callLock.isHeldByCurrentThread()) { - throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); - } - this.createCopy = createCopy; - // Increment regardless of whether copy will be created or not to return null from getCopy() - return ++this.copyKey; - } - - @Override - public IChunkGet getCopy(final int key) { - return copies.remove(key); - } - - @Override - public void lockCall() { - this.callLock.lock(); - } - - @Override - public void unlockCall() { - this.callLock.unlock(); - } - - @Override - public void setLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { - if (light != null) { - lightUpdate = true; - try { - fillLightNibble(light, LightLayer.BLOCK, minSectionPosition, maxSectionPosition); - } catch (Throwable e) { - e.printStackTrace(); - } - } - } - - @Override - public void setSkyLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { - if (light != null) { - lightUpdate = true; - try { - fillLightNibble(light, LightLayer.SKY, minSectionPosition, maxSectionPosition); - } catch (Throwable e) { - e.printStackTrace(); - } - } - } - - @Override - public void setHeightmapToGet(HeightMapType type, int[] data) { - // height + 1 to match server internal - BitArrayUnstretched bitArray = new BitArrayUnstretched(MathMan.log2nlz(getChunk().getHeight() + 1), 256); - bitArray.fromRaw(data); - Heightmap.Types nativeType = Heightmap.Types.valueOf(type.name()); - Heightmap heightMap = getChunk().heightmaps.get(nativeType); - heightMap.setRawData(getChunk(), nativeType, bitArray.getData()); - } - - @Override - public int getMaxY() { - return maxHeight; - } - - @Override - public int getMinY() { - return minHeight; - } - - @Override - public BiomeType getBiomeType(int x, int y, int z) { - ChunkBiomeContainer index = getChunk().getBiomes(); - Biome biomes = null; - if (y == -1) { - for (y = serverLevel.getMinBuildHeight(); y < serverLevel.getMaxBuildHeight(); y += 4) { - biomes = index.getNoiseBiome(x >> 2, y >> 2, z >> 2); - if (biomes != null) { - break; - } - } - } else { - biomes = index.getNoiseBiome(x >> 2, y >> 2, z >> 2); - } - return biomes != null ? PaperweightPlatformAdapter.adapt(biomes, serverLevel) : null; - } - - @Override - public void removeSectionLighting(int layer, boolean sky) { - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.BLOCK).getDataLayerData( - sectionPos); - if (dataLayer != null) { - lightUpdate = true; - synchronized (dataLayer) { - byte[] bytes = PaperLib.isPaper() ? dataLayer.getIfSet() : dataLayer.getData(); - if (!PaperLib.isPaper() || bytes != DataLayer.EMPTY_NIBBLE) { - Arrays.fill(bytes, (byte) 0); - } - } - } - if (sky) { - SectionPos sectionPos1 = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer1 = serverLevel - .getChunkSource() - .getLightEngine() - .getLayerListener(LightLayer.SKY) - .getDataLayerData(sectionPos1); - if (dataLayer1 != null) { - lightUpdate = true; - synchronized (dataLayer1) { - byte[] bytes = PaperLib.isPaper() ? dataLayer1.getIfSet() : dataLayer1.getData(); - if (!PaperLib.isPaper() || bytes != DataLayer.EMPTY_NIBBLE) { - Arrays.fill(bytes, (byte) 0); - } - } - } - } - } - - @Override - public CompoundTag getTile(int x, int y, int z) { - BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( - chunkX << 4), y, (z & 15) + ( - chunkZ << 4))); - if (blockEntity == null) { - return null; - } - return new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.save(new net.minecraft.nbt.CompoundTag()))); - } - - @Override - public Map getTiles() { - Map nmsTiles = getChunk().getBlockEntities(); - if (nmsTiles.isEmpty()) { - return Collections.emptyMap(); - } - return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); - } - - @Override - public int getSkyLight(int x, int y, int z) { - int layer = y >> 4; - int alayer = layer - getMinSectionPosition(); - if (skyLight[alayer] == null) { - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = - serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.SKY).getDataLayerData(sectionPos); - // If the server hasn't generated the section's NibbleArray yet, it will be null - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. - Arrays.fill(LAYER_COUNT, (byte) 15); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( - LightLayer.BLOCK, - sectionPos, - dataLayer, - true - ); - } - skyLight[alayer] = dataLayer; - } - return skyLight[alayer].get(x & 15, y & 15, z & 15); - } - - @Override - public int getEmittedLight(int x, int y, int z) { - int layer = y >> 4; - int alayer = layer - getMinSectionPosition(); - if (blockLight[alayer] == null) { - serverLevel.getRawBrightness(new BlockPos(1, 1, 1), 5); - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = serverLevel - .getChunkSource() - .getLightEngine() - .getLayerListener(LightLayer.BLOCK) - .getDataLayerData(sectionPos); - // If the server hasn't generated the section's DataLayer yet, it will be null - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. - Arrays.fill(LAYER_COUNT, (byte) 15); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos, - dataLayer, true - ); - } - blockLight[alayer] = dataLayer; - } - return blockLight[alayer].get(x & 15, y & 15, z & 15); - } - - @Override - public int[] getHeightMap(HeightMapType type) { - long[] longArray = getChunk().heightmaps.get(Heightmap.Types.valueOf(type.name())).getRawData(); - BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256, longArray); - return bitArray.toRaw(new int[256]); - } - - @Override - public CompoundTag getEntity(UUID uuid) { - Entity entity = serverLevel.getEntity(uuid); - if (entity != null) { - org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); - return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); - } - for (CompoundTag tag : getEntities()) { - if (uuid.equals(tag.getUUID())) { - return tag; - } - } - return null; - } - - @Override - public Set getEntities() { - List entities = PaperweightPlatformAdapter.getEntities(getChunk()); - if (entities.isEmpty()) { - return Collections.emptySet(); - } - int size = entities.size(); - return new AbstractSet<>() { - @Override - public int size() { - return size; - } - - @Override - public boolean isEmpty() { - return false; - } - - @Override - public boolean contains(Object get) { - if (!(get instanceof CompoundTag getTag)) { - return false; - } - UUID getUUID = getTag.getUUID(); - for (Entity entity : entities) { - UUID uuid = entity.getUUID(); - if (uuid.equals(getUUID)) { - return true; - } - } - return false; - } - - @Nonnull - @Override - public Iterator iterator() { - Iterable result = entities.stream().map(input -> { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(input, tag); - return (CompoundTag) adapter.toNative(tag); - }).collect(Collectors.toList()); - return result.iterator(); - } - }; - } - - private void removeEntity(Entity entity) { - entity.discard(); - } - - public LevelChunk ensureLoaded(ServerLevel nmsWorld, int chunkX, int chunkZ) { - return PaperweightPlatformAdapter.ensureLoaded(nmsWorld, chunkX, chunkZ); - } - - @Override - @SuppressWarnings("rawtypes") - public synchronized > T call(IChunkSet set, Runnable finalizer) { - if (!callLock.isHeldByCurrentThread()) { - throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked."); - } - forceLoadSections = false; - PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; - if (createCopy) { - if (copies.containsKey(copyKey)) { - throw new IllegalStateException("Copy key already used."); - } - copies.put(copyKey, copy); - } - try { - ServerLevel nmsWorld = serverLevel; - LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); - boolean fastmode = set.isFastMode() && Settings.settings().QUEUE.NO_TICK_FASTMODE; - - // Remove existing tiles. Create a copy so that we can remove blocks - Map chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); - List beacons = null; - if (!chunkTiles.isEmpty()) { - for (Map.Entry entry : chunkTiles.entrySet()) { - final BlockPos pos = entry.getKey(); - final int lx = pos.getX() & 15; - final int ly = pos.getY(); - final int lz = pos.getZ() & 15; - final int layer = ly >> 4; - if (!set.hasSection(layer)) { - continue; - } - - int ordinal = set.getBlock(lx, ly, lz).getOrdinal(); - if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) { - BlockEntity tile = entry.getValue(); - if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) { - if (beacons == null) { - beacons = new ArrayList<>(); - } - beacons.add(tile); - PaperweightPlatformAdapter.removeBeacon(tile, nmsChunk); - continue; - } - nmsChunk.removeBlockEntity(tile.getBlockPos()); - if (createCopy) { - copy.storeTile(tile); - } - } - } - } - - int bitMask = 0; - synchronized (nmsChunk) { - LevelChunkSection[] levelChunkSections = nmsChunk.getSections(); - - for (int layerNo = getMinSectionPosition(); layerNo <= getMaxSectionPosition(); layerNo++) { - if (!set.hasSection(layerNo)) { - continue; - } - int layer = layerNo - getMinSectionPosition(); - - bitMask |= 1 << layer; - - // setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to - // this chunk GET when #updateGet is called. Future dords, please listen this time. - char[] tmp = set.load(layerNo); - char[] setArr = new char[tmp.length]; - System.arraycopy(tmp, 0, setArr, 0, tmp.length); - - // synchronise on internal section to avoid circular locking with a continuing edit if the chunk was - // submitted to keep loaded internal chunks to queue target size. - synchronized (super.sectionLocks[layer]) { - if (createCopy) { - char[] tmpLoad = loadPrivately(layerNo); - char[] copyArr = new char[4096]; - System.arraycopy(tmpLoad, 0, copyArr, 0, 4096); - copy.storeSection(layer, copyArr); - } - - LevelChunkSection newSection; - LevelChunkSection existingSection = levelChunkSections[layer]; - // Don't attempt to tick section whilst we're editing - if (existingSection != null) { - PaperweightPlatformAdapter.clearCounts(existingSection); - if (PaperLib.isPaper()) { - existingSection.tickingList.clear(); - } - } - - if (existingSection == null) { - newSection = PaperweightPlatformAdapter.newChunkSection(layerNo, setArr, fastmode, adapter); - if (PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, null, newSection, layer)) { - updateGet(nmsChunk, levelChunkSections, newSection, setArr, layer); - continue; - } else { - existingSection = levelChunkSections[layer]; - if (existingSection == null) { - LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - +layer - ); - continue; - } - } - } - - //ensure that the server doesn't try to tick the chunksection while we're editing it (again). - PaperweightPlatformAdapter.clearCounts(existingSection); - if (PaperLib.isPaper()) { - existingSection.tickingList.clear(); - } - DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); - - // Synchronize to prevent further acquisitions - synchronized (lock) { - lock.acquire(); // Wait until we have the lock - lock.release(); - try { - sectionLock.writeLock().lock(); - if (this.getChunk() != nmsChunk) { - this.levelChunk = nmsChunk; - this.sections = null; - this.reset(); - } else if (existingSection != getSections(false)[layer]) { - this.sections[layer] = existingSection; - this.reset(); - } else if (!Arrays.equals(update(layer, new char[4096], true), loadPrivately(layerNo))) { - this.reset(layerNo); - /*} else if (lock.isModified()) { - this.reset(layerNo);*/ - } - } finally { - sectionLock.writeLock().unlock(); - } - newSection = - PaperweightPlatformAdapter.newChunkSection( - layerNo, - this::loadPrivately, - setArr, - fastmode, - adapter - ); - if (!PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - existingSection, - newSection, - layer - )) { - LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - +layer - ); - } else { - updateGet(nmsChunk, levelChunkSections, newSection, setArr, layer); - } - } - } - } - - // Biomes - BiomeType[][] biomes = set.getBiomes(); - if (biomes != null) { - // set biomes - ChunkBiomeContainer currentBiomes = nmsChunk.getBiomes(); - if (createCopy) { - copy.storeBiomes(currentBiomes); - } - for (int layer = 0; layer < 16; layer++) { - if (biomes[layer] == null) { - continue; - } - for (int y = 0, i = 0; y < 4; y++) { - for (int z = 0; z < 4; z++) { - for (int x = 0; x < 4; x++, i++) { - final BiomeType biome = biomes[layer][i]; - if (biome != null) { - Biome nmsBiome = - nmsWorld.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY).get( - ResourceLocation.tryParse(biome.getId())); - if (nmsBiome == null) { - throw new NullPointerException("BiomeBase null for BiomeType " + biome.getId()); - } - currentBiomes.setBiome(x, (layer << 2) + y, z, nmsBiome); - } - } - } - } - } - } - - Map heightMaps = set.getHeightMaps(); - for (Map.Entry entry : heightMaps.entrySet()) { - PaperweightGetBlocks.this.setHeightmapToGet(entry.getKey(), entry.getValue()); - } - PaperweightGetBlocks.this.setLightingToGet( - set.getLight(), - set.getMinSectionPosition(), - set.getMaxSectionPosition() - ); - PaperweightGetBlocks.this.setSkyLightingToGet( - set.getSkyLight(), - set.getMinSectionPosition(), - set.getMaxSectionPosition() - ); - - Runnable[] syncTasks = null; - - int bx = chunkX << 4; - int bz = chunkZ << 4; - - // Call beacon deactivate events here synchronously - // list will be null on spigot, so this is an implicit isPaper check - if (beacons != null && !beacons.isEmpty()) { - final List finalBeacons = beacons; - - syncTasks = new Runnable[4]; - - syncTasks[3] = () -> { - for (BlockEntity beacon : finalBeacons) { - BeaconBlockEntity.playSound(beacon.getLevel(), beacon.getBlockPos(), SoundEvents.BEACON_DEACTIVATE); - new BeaconDeactivatedEvent(CraftBlock.at(beacon.getLevel(), beacon.getBlockPos())).callEvent(); - } - }; - } - - Set entityRemoves = set.getEntityRemoves(); - if (entityRemoves != null && !entityRemoves.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[3]; - } - - syncTasks[2] = () -> { - Set entitiesRemoved = new HashSet<>(); - final List entities = PaperweightPlatformAdapter.getEntities(nmsChunk); - - for (Entity entity : entities) { - UUID uuid = entity.getUUID(); - if (entityRemoves.contains(uuid)) { - if (createCopy) { - copy.storeEntity(entity); - } - removeEntity(entity); - entitiesRemoved.add(uuid); - entityRemoves.remove(uuid); - } - } - if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { - for (UUID uuid : entityRemoves) { - Entity entity = nmsWorld.entityManager.getEntityGetter().get(uuid); - if (entity != null) { - removeEntity(entity); - } - } - } - // Only save entities that were actually removed to history - set.getEntityRemoves().clear(); - set.getEntityRemoves().addAll(entitiesRemoved); - }; - } - - Set entities = set.getEntities(); - if (entities != null && !entities.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[2]; - } - - syncTasks[1] = () -> { - Iterator iterator = entities.iterator(); - while (iterator.hasNext()) { - final CompoundTag nativeTag = iterator.next(); - final Map entityTagMap = nativeTag.getValue(); - final StringTag idTag = (StringTag) entityTagMap.get("Id"); - final ListTag posTag = (ListTag) entityTagMap.get("Pos"); - final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); - if (idTag == null || posTag == null || rotTag == null) { - LOGGER.error("Unknown entity tag: {}", nativeTag); - continue; - } - final double x = posTag.getDouble(0); - final double y = posTag.getDouble(1); - final double z = posTag.getDouble(2); - final float yaw = rotTag.getFloat(0); - final float pitch = rotTag.getFloat(1); - final String id = idTag.getValue(); - - EntityType type = EntityType.byString(id).orElse(null); - if (type != null) { - Entity entity = type.create(nmsWorld); - if (entity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); - for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - entity.load(tag); - entity.absMoveTo(x, y, z, yaw, pitch); - entity.setUUID(nativeTag.getUUID()); - if (!nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { - LOGGER.warn( - "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", - id, - nmsWorld.getWorld().getName(), - x, - y, - z - ); - // Unsuccessful create should not be saved to history - iterator.remove(); - } - } - } - } - }; - } - - // set tiles - Map tiles = set.getTiles(); - if (tiles != null && !tiles.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[1]; - } - - syncTasks[0] = () -> { - for (final Map.Entry entry : tiles.entrySet()) { - final CompoundTag nativeTag = entry.getValue(); - final BlockVector3 blockHash = entry.getKey(); - final int x = blockHash.getX() + bx; - final int y = blockHash.getY(); - final int z = blockHash.getZ() + bz; - final BlockPos pos = new BlockPos(x, y, z); - - synchronized (nmsWorld) { - BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); - if (tileEntity == null || tileEntity.isRemoved()) { - nmsWorld.removeBlockEntity(pos); - tileEntity = nmsWorld.getBlockEntity(pos); - } - if (tileEntity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); - tag.put("x", IntTag.valueOf(x)); - tag.put("y", IntTag.valueOf(y)); - tag.put("z", IntTag.valueOf(z)); - tileEntity.load(tag); - } - } - } - }; - } - - Runnable callback; - if (bitMask == 0 && biomes == null && !lightUpdate) { - callback = null; - } else { - int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; - boolean finalLightUpdate = lightUpdate; - callback = () -> { - // Set Modified - nmsChunk.setLightCorrect(true); // Set Modified - nmsChunk.mustNotSave = false; - nmsChunk.markUnsaved(); - // send to player - if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { - this.send(finalMask, finalLightUpdate); - } - if (finalizer != null) { - finalizer.run(); - } - }; - } - if (syncTasks != null) { - QueueHandler queueHandler = Fawe.instance().getQueueHandler(); - Runnable[] finalSyncTasks = syncTasks; - - // Chain the sync tasks and the callback - Callable chain = () -> { - try { - // Run the sync tasks - for (Runnable task : finalSyncTasks) { - if (task != null) { - task.run(); - } - } - if (callback == null) { - if (finalizer != null) { - finalizer.run(); - } - return null; - } else { - return queueHandler.async(callback, null); - } - } catch (Throwable e) { - e.printStackTrace(); - throw e; - } - }; - //noinspection unchecked - required at compile time - return (T) (Future) queueHandler.sync(chain); - } else { - if (callback == null) { - if (finalizer != null) { - finalizer.run(); - } - } else { - callback.run(); - } - } - } - return null; - } catch (Throwable e) { - e.printStackTrace(); - return null; - } finally { - forceLoadSections = true; - } - } - - private void updateGet( - LevelChunk nmsChunk, - LevelChunkSection[] chunkSections, - LevelChunkSection section, - char[] arr, - int layer - ) { - try { - sectionLock.writeLock().lock(); - if (this.getChunk() != nmsChunk) { - this.levelChunk = nmsChunk; - this.sections = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); - this.reset(); - } - if (this.sections == null) { - this.sections = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); - } - if (this.sections[layer] != section) { - // Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords - this.sections[layer] = new LevelChunkSection[]{section}.clone()[0]; - } - } finally { - sectionLock.writeLock().unlock(); - } - this.blocks[layer] = arr; - } - - private char[] loadPrivately(int layer) { - layer -= getMinSectionPosition(); - if (super.sections[layer] != null) { - synchronized (super.sectionLocks[layer]) { - if (super.sections[layer].isFull() && super.blocks[layer] != null) { - return super.blocks[layer]; - } - } - } - return PaperweightGetBlocks.this.update(layer, null, true); - } - - @Override - public void send(int mask, boolean lighting) { - synchronized (sendLock) { - PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); - } - } - - /** - * Update a given (nullable) data array to the current data stored in the server's chunk, associated with this - * {@link PaperweightPlatformAdapter} instance. Not synchronised to the {@link PaperweightPlatformAdapter} instance as synchronisation - * is handled where necessary in the method, and should otherwise be handled correctly by this method's caller. - * - * @param layer layer index (0 may denote a negative layer in the world, e.g. at y=-32) - * @param data array to be updated/filled with data or null - * @param aggressive if the cached section array should be re-acquired. - * @return the given array to be filled with data, or a new array if null is given. - */ - @Override - @SuppressWarnings("unchecked") - public char[] update(int layer, char[] data, boolean aggressive) { - LevelChunkSection section = getSections(aggressive)[layer]; - // Section is null, return empty array - if (section == null) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - return data; - } - if (data != null && data.length != 4096) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - } - if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - } - Semaphore lock = PaperweightPlatformAdapter.applyLock(section); - synchronized (lock) { - // Efficiently convert ChunkSection to raw data - try { - lock.acquire(); - - final PalettedContainer blocks = section.getStates(); - final BitStorage bits = (BitStorage) PaperweightPlatformAdapter.fieldStorage.get(blocks); - final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get(blocks); - - final int bitsPerEntry = (int) PaperweightPlatformAdapter.fieldBitsPerEntry.get(bits); - final long[] blockStates = bits.getRaw(); - - new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).toRaw(data); - - int num_palette; - if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { - num_palette = palette.getSize(); - } else { - // The section's palette is the global block palette. - for (int i = 0; i < 4096; i++) { - char paletteVal = data[i]; - char ordinal = adapter.ibdIDToOrdinal(paletteVal); - data[i] = ordinal; - } - return data; - } - - char[] paletteToOrdinal = FaweCache.INSTANCE.PALETTE_TO_BLOCK_CHAR.get(); - try { - if (num_palette != 1) { - for (int i = 0; i < num_palette; i++) { - char ordinal = ordinal(palette.valueFor(i), adapter); - paletteToOrdinal[i] = ordinal; - } - for (int i = 0; i < 4096; i++) { - char paletteVal = data[i]; - char val = paletteToOrdinal[paletteVal]; - if (val == Character.MAX_VALUE) { - val = ordinal(palette.valueFor(i), adapter); - paletteToOrdinal[i] = val; - } - data[i] = val; - } - } else { - char ordinal = ordinal(palette.valueFor(0), adapter); - Arrays.fill(data, ordinal); - } - } finally { - for (int i = 0; i < num_palette; i++) { - paletteToOrdinal[i] = Character.MAX_VALUE; - } - } - return data; - } catch (IllegalAccessException | InterruptedException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } finally { - lock.release(); - } - } - } - - private char ordinal(net.minecraft.world.level.block.state.BlockState ibd, PaperweightFaweAdapter adapter) { - if (ibd == null) { - return BlockTypesCache.ReservedIDs.AIR; - } else { - return adapter.adaptToChar(ibd); - } - } - - public LevelChunkSection[] getSections(boolean force) { - force &= forceLoadSections; - LevelChunkSection[] tmp = sections; - if (tmp == null || force) { - try { - sectionLock.writeLock().lock(); - tmp = sections; - if (tmp == null || force) { - LevelChunkSection[] chunkSections = getChunk().getSections(); - tmp = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length); - sections = tmp; - } - } finally { - sectionLock.writeLock().unlock(); - } - } - return tmp; - } - - public LevelChunk getChunk() { - LevelChunk levelChunk = this.levelChunk; - if (levelChunk == null) { - synchronized (this) { - levelChunk = this.levelChunk; - if (levelChunk == null) { - this.levelChunk = levelChunk = ensureLoaded(this.serverLevel, chunkX, chunkZ); - } - } - } - return levelChunk; - } - - private void fillLightNibble(char[][] light, LightLayer lightLayer, int minSectionPosition, int maxSectionPosition) { - for (int Y = 0; Y <= maxSectionPosition - minSectionPosition; Y++) { - if (light[Y] == null) { - continue; - } - SectionPos sectionPos = SectionPos.of(levelChunk.getPos(), Y + minSectionPosition); - DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(lightLayer).getDataLayerData( - sectionPos); - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - Arrays.fill(LAYER_COUNT, lightLayer == LightLayer.SKY ? (byte) 15 : (byte) 0); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( - lightLayer, - sectionPos, - dataLayer, - true - ); - } - synchronized (dataLayer) { - for (int x = 0; x < 16; x++) { - for (int y = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { - int i = y << 8 | z << 4 | x; - if (light[Y][i] < 16) { - dataLayer.set(x, y, z, light[Y][i]); - } - } - } - } - } - } - } - - @Override - public boolean hasSection(int layer) { - layer -= getMinSectionPosition(); - return getSections(false)[layer] != null; - } - - @Override - @SuppressWarnings("unchecked") - public synchronized boolean trim(boolean aggressive) { - skyLight = new DataLayer[getSectionCount()]; - blockLight = new DataLayer[getSectionCount()]; - if (aggressive) { - sectionLock.writeLock().lock(); - sections = null; - levelChunk = null; - sectionLock.writeLock().unlock(); - return super.trim(true); - } else if (sections == null) { - // don't bother trimming if there are no sections stored. - return true; - } else { - for (int i = getMinSectionPosition(); i <= getMaxSectionPosition(); i++) { - int layer = i - getMinSectionPosition(); - if (!hasSection(i) || !super.sections[layer].isFull()) { - continue; - } - LevelChunkSection existing = getSections(true)[layer]; - try { - final PalettedContainer blocksExisting = existing.getStates(); - - final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get( - blocksExisting); - int paletteSize; - - if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { - paletteSize = palette.getSize(); - } else { - super.trim(false, i); - continue; - } - if (paletteSize == 1) { - //If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks. - continue; - } - super.trim(false, i); - } catch (IllegalAccessException ignored) { - super.trim(false, i); - } - } - return true; - } - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java deleted file mode 100644 index cd9987d79..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java +++ /dev/null @@ -1,251 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; - -import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; -import com.fastasyncworldedit.core.queue.IBlocks; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.math.BlockVector3; -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.BlockTypesCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.ChunkBiomeContainer; -import net.minecraft.world.level.chunk.LevelChunk; - -import javax.annotation.Nullable; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Future; - -public class PaperweightGetBlocks_Copy implements IChunkGet { - - private final Map tiles = new HashMap<>(); - private final Set entities = new HashSet<>(); - private final char[][] blocks; - private final int minHeight; - private final int maxHeight; - final ServerLevel serverLevel; - final LevelChunk levelChunk; - private ChunkBiomeContainer chunkBiomeContainer; - - protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { - this.levelChunk = levelChunk; - this.serverLevel = levelChunk.level; - this.minHeight = serverLevel.getMinBuildHeight(); - this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. - this.blocks = new char[getSectionCount()][]; - } - - protected void storeTile(BlockEntity blockEntity) { - tiles.put( - BlockVector3.at( - blockEntity.getBlockPos().getX(), - blockEntity.getBlockPos().getY(), - blockEntity.getBlockPos().getZ() - ), - new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.save(new net.minecraft.nbt.CompoundTag()))) - ); - } - - @Override - public Map getTiles() { - return tiles; - } - - @Override - @Nullable - public CompoundTag getTile(int x, int y, int z) { - return tiles.get(BlockVector3.at(x, y, z)); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - protected void storeEntity(Entity entity) { - BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(entity, compoundTag); - entities.add((CompoundTag) adapter.toNative(compoundTag)); - } - - @Override - public Set getEntities() { - return this.entities; - } - - @Override - public CompoundTag getEntity(UUID uuid) { - for (CompoundTag tag : entities) { - if (uuid.equals(tag.getUUID())) { - return tag; - } - } - return null; - } - - @Override - public boolean isCreateCopy() { - return false; - } - - @Override - public int setCreateCopy(boolean createCopy) { - return -1; - } - - @Override - public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { - } - - @Override - public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { - } - - @Override - public void setHeightmapToGet(HeightMapType type, int[] data) { - } - - @Override - public int getMaxY() { - return maxHeight; - } - - @Override - public int getMinY() { - return minHeight; - } - - @Override - public int getMaxSectionPosition() { - return maxHeight >> 4; - } - - @Override - public int getMinSectionPosition() { - return minHeight >> 4; - } - - protected void storeBiomes(ChunkBiomeContainer chunkBiomeContainer) { - // The to do one line below is pre-paperweight and needs to be revised - // TODO revisit last parameter, BiomeStorage[] *would* be more efficient - this.chunkBiomeContainer = new ChunkBiomeContainer(chunkBiomeContainer.biomeRegistry, serverLevel, - chunkBiomeContainer.writeBiomes() - ); - } - - @Override - public BiomeType getBiomeType(int x, int y, int z) { - Biome biome = null; - if (y == -1) { - for (y = serverLevel.getMinBuildHeight(); y <= serverLevel.getMaxBuildHeight(); y += 4) { - biome = this.chunkBiomeContainer.getNoiseBiome(x >> 2, y >> 2, z >> 2); - if (biome != null) { - break; - } - } - } else { - biome = this.chunkBiomeContainer.getNoiseBiome(x >> 2, y >> 2, z >> 2); - } - return biome != null ? PaperweightPlatformAdapter.adapt(biome, serverLevel) : null; - } - - @Override - public void removeSectionLighting(int layer, boolean sky) { - } - - @Override - public boolean trim(boolean aggressive, int layer) { - return false; - } - - @Override - public IBlocks reset() { - return null; - } - - @Override - public int getSectionCount() { - return serverLevel.getSectionsCount(); - } - - protected void storeSection(int layer, char[] data) { - blocks[layer] = data; - } - - @Override - public BaseBlock getFullBlock(int x, int y, int z) { - BlockState state = BlockTypesCache.states[get(x, y, z)]; - return state.toBaseBlock(this, x, y, z); - } - - @Override - public boolean hasSection(int layer) { - layer -= getMinSectionPosition(); - return blocks[layer] != null; - } - - @Override - public char[] load(int layer) { - layer -= getMinSectionPosition(); - if (blocks[layer] == null) { - blocks[layer] = new char[4096]; - Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR); - } - return blocks[layer]; - } - - @Override - public char[] loadIfPresent(int layer) { - layer -= getMinSectionPosition(); - return blocks[layer]; - } - - @Override - public BlockState getBlock(int x, int y, int z) { - return BlockTypesCache.states[get(x, y, z)]; - } - - @Override - public int getSkyLight(int x, int y, int z) { - return 0; - } - - @Override - public int getEmittedLight(int x, int y, int z) { - return 0; - } - - @Override - public int[] getHeightMap(HeightMapType type) { - return new int[0]; - } - - @Override - public > T call(IChunkSet set, Runnable finalize) { - return null; - } - - public char get(int x, int y, int z) { - final int layer = (y >> 4) - getMinSectionPosition(); - final int index = (y & 15) << 8 | z << 4 | x; - return blocks[layer][index]; - } - - - @Override - public boolean trim(boolean aggressive) { - return false; - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightMapChunkUtil.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightMapChunkUtil.java deleted file mode 100644 index c9d5ed124..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightMapChunkUtil.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; - -import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import net.minecraft.network.protocol.game.ClientboundLevelChunkPacket; - -public class PaperweightMapChunkUtil extends MapChunkUtil { - - public PaperweightMapChunkUtil() throws NoSuchFieldException { - fieldX = ClientboundLevelChunkPacket.class.getDeclaredField(Refraction.pickName("TWO_MEGABYTES", "a")); - fieldZ = ClientboundLevelChunkPacket.class.getDeclaredField(Refraction.pickName("x", "b")); - fieldBitMask = ClientboundLevelChunkPacket.class.getDeclaredField(Refraction.pickName("z", "c")); - fieldHeightMap = ClientboundLevelChunkPacket.class.getDeclaredField(Refraction.pickName("availableSections", "d")); - fieldChunkData = ClientboundLevelChunkPacket.class.getDeclaredField(Refraction.pickName("biomes", "f")); - fieldBlockEntities = ClientboundLevelChunkPacket.class.getDeclaredField(Refraction.pickName("buffer", "g")); - fieldFull = ClientboundLevelChunkPacket.class.getDeclaredField(Refraction.pickName("blockEntitiesTags", "h")); - fieldX.setAccessible(true); - fieldZ.setAccessible(true); - fieldBitMask.setAccessible(true); - fieldHeightMap.setAccessible(true); - fieldChunkData.setAccessible(true); - fieldBlockEntities.setAccessible(true); - fieldFull.setAccessible(true); - } - - @Override - public ClientboundLevelChunkPacket createPacket() { - // TODO ??? return new ClientboundLevelChunkPacket(); - throw new UnsupportedOperationException(); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java deleted file mode 100644 index 16dfd7bd8..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java +++ /dev/null @@ -1,526 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; - -import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; -import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; -import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.math.BitArrayUnstretched; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.ReflectionUtils; -import com.fastasyncworldedit.core.util.TaskManager; -import com.mojang.datafixers.util.Either; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -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.BlockTypesCache; -import io.papermc.lib.PaperLib; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.network.protocol.game.ClientboundLevelChunkPacket; -import net.minecraft.network.protocol.game.ClientboundLightUpdatePacket; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.level.TicketType; -import net.minecraft.util.BitStorage; -import net.minecraft.util.Unit; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.npc.AbstractVillager; -import net.minecraft.world.item.trading.MerchantOffers; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.EntityBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.ChunkBiomeContainer; -import net.minecraft.world.level.chunk.HashMapPalette; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.LinearPalette; -import net.minecraft.world.level.chunk.Palette; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.gameevent.GameEventDispatcher; -import net.minecraft.world.level.gameevent.GameEventListener; -import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; -import sun.misc.Unsafe; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.function.Function; -import java.util.stream.Stream; - -public final class PaperweightPlatformAdapter extends NMSAdapter { - - public static final Field fieldStorage; - public static final Field fieldPalette; - public static final Field fieldBits; - - public static final Field fieldBitsPerEntry; - - private static final Field fieldTickingFluidContent; - private static final Field fieldTickingBlockCount; - private static final Field fieldNonEmptyBlockCount; - - private static final Field fieldBiomes; - - private static final MethodHandle methodGetVisibleChunk; - - private static final Field fieldLock; - - private static final Field fieldGameEventDispatcherSections; - private static final MethodHandle methodremoveBlockEntityTicker; - - private static final Field fieldOffers; - private static final MerchantOffers OFFERS = new MerchantOffers(); - - private static final Field fieldRemove; - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - static { - try { - fieldBits = PalettedContainer.class.getDeclaredField(Refraction.pickName("bits", "l")); - fieldBits.setAccessible(true); - fieldStorage = PalettedContainer.class.getDeclaredField(Refraction.pickName("storage", "c")); - fieldStorage.setAccessible(true); - fieldPalette = PalettedContainer.class.getDeclaredField(Refraction.pickName("palette", "k")); - fieldPalette.setAccessible(true); - - fieldBitsPerEntry = BitStorage.class.getDeclaredField(Refraction.pickName("bits", "c")); - fieldBitsPerEntry.setAccessible(true); - - fieldTickingFluidContent = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "h")); - fieldTickingFluidContent.setAccessible(true); - fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g")); - fieldTickingBlockCount.setAccessible(true); - fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f")); - fieldNonEmptyBlockCount.setAccessible(true); - - fieldBiomes = ChunkBiomeContainer.class.getDeclaredField(Refraction.pickName("biomes", "f")); - fieldBiomes.setAccessible(true); - - Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( - "getVisibleChunkIfPresent", - "getVisibleChunk" - ), long.class); - getVisibleChunkIfPresent.setAccessible(true); - methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent); - - if (!PaperLib.isPaper()) { - fieldLock = PalettedContainer.class.getDeclaredField(Refraction.pickName("lock", "m")); - fieldLock.setAccessible(true); - } else { - // in paper, the used methods are synchronized properly - fieldLock = null; - } - - fieldGameEventDispatcherSections = LevelChunk.class.getDeclaredField(Refraction.pickName( - "gameEventDispatcherSections", "x")); - fieldGameEventDispatcherSections.setAccessible(true); - Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod( - Refraction.pickName( - "removeBlockEntityTicker", - "l" - ), BlockPos.class - ); - removeBlockEntityTicker.setAccessible(true); - methodremoveBlockEntityTicker = MethodHandles.lookup().unreflect(removeBlockEntityTicker); - - fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p")); - fieldRemove.setAccessible(true); - - fieldOffers = AbstractVillager.class.getDeclaredField(Refraction.pickName("offers", "bU")); - fieldOffers.setAccessible(true); - } catch (RuntimeException e) { - throw e; - } catch (Throwable rethrow) { - rethrow.printStackTrace(); - throw new RuntimeException(rethrow); - } - } - - static boolean setSectionAtomic( - LevelChunkSection[] sections, - LevelChunkSection expected, - LevelChunkSection value, - int layer - ) { - if (layer >= 0 && layer < sections.length) { - return ReflectionUtils.compareAndSet(sections, expected, value, layer); - } - return false; - } - - // There is no point in having a functional semaphore for paper servers. - private static final ThreadLocal SEMAPHORE_THREAD_LOCAL = - ThreadLocal.withInitial(() -> new DelegateSemaphore(1, null)); - - static DelegateSemaphore applyLock(LevelChunkSection section) { - if (PaperLib.isPaper()) { - return SEMAPHORE_THREAD_LOCAL.get(); - } - try { - synchronized (section) { - PalettedContainer blocks = section.getStates(); - Semaphore currentLock = (Semaphore) fieldLock.get(blocks); - if (currentLock instanceof DelegateSemaphore delegateSemaphore) { - return delegateSemaphore; - } - DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); - fieldLock.set(blocks, newLock); - return newLock; - } - } catch (Throwable e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - } - - public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) { - if (!PaperLib.isPaper()) { - LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false); - if (nmsChunk != null) { - return nmsChunk; - } - if (Fawe.isMainThread()) { - return serverLevel.getChunk(chunkX, chunkZ); - } - } else { - LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ); - if (nmsChunk != null) { - addTicket(serverLevel, chunkX, chunkZ); - return nmsChunk; - } - nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ); - if (nmsChunk != null) { - addTicket(serverLevel, chunkX, chunkZ); - return nmsChunk; - } - // Avoid "async" methods from the main thread. - if (Fawe.isMainThread()) { - return serverLevel.getChunk(chunkX, chunkZ); - } - CompletableFuture future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true); - try { - CraftChunk chunk; - try { - chunk = (CraftChunk) future.get(10, TimeUnit.SECONDS); - } catch (TimeoutException e) { - String world = serverLevel.getWorld().getName(); - // We've already taken 10 seconds we can afford to wait a little here. - boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null); - if (loaded) { - LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world); - // Retry chunk load - chunk = (CraftChunk) serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true).get(); - } else { - throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!"); - } - } - return chunk.getHandle(); - } catch (Throwable e) { - e.printStackTrace(); - } - } - return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)); - } - - private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) { - // Ensure chunk is definitely loaded before applying a ticket - net.minecraft.server.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel - .getChunkSource() - .addRegionTicket(TicketType.PLUGIN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE)); - } - - public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) { - ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap; - try { - return (ChunkHolder) methodGetVisibleChunk.invoke(chunkMap, ChunkPos.asLong(chunkX, chunkZ)); - } catch (Throwable thr) { - throw new RuntimeException(thr); - } - } - - @SuppressWarnings("unchecked") - public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) { - ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); - if (chunkHolder == null) { - return; - } - ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ); - // UNLOADED_CHUNK - Optional optional = ((Either) chunkHolder - .getTickingChunkFuture() - .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left(); - if (PaperLib.isPaper()) { - // getChunkAtIfLoadedImmediately is paper only - optional = optional.or(() -> Optional.ofNullable(nmsWorld - .getChunkSource() - .getChunkAtIfLoadedImmediately(chunkX, chunkZ))); - } - if (optional.isEmpty()) { - return; - } - LevelChunk levelChunk = optional.get(); - TaskManager.taskManager().task(() -> { - ClientboundLevelChunkPacket chunkPacket = new ClientboundLevelChunkPacket(levelChunk); - nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(chunkPacket)); - if (lighting) { - //This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad) - boolean trustEdges = true; - ClientboundLightUpdatePacket packet = - new ClientboundLightUpdatePacket(coordIntPair, nmsWorld.getChunkSource().getLightEngine(), null, null, - trustEdges - ); - nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); - } - }); - } - - private static Stream nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) { - return serverLevel.getChunkSource().chunkMap.getPlayers(coordIntPair, false); - } - - /* - NMS conversion - */ - public static LevelChunkSection newChunkSection( - final int layer, - final char[] blocks, - boolean fastMode, - CachedBukkitAdapter adapter - ) { - return newChunkSection(layer, null, blocks, fastMode, adapter); - } - - public static LevelChunkSection newChunkSection( - final int layer, - final Function get, - char[] set, - boolean fastMode, - CachedBukkitAdapter adapter - ) { - if (set == null) { - return newChunkSection(layer); - } - final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); - final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); - final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get(); - final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get(); - try { - int num_palette; - final short[] nonEmptyBlockCount = fastMode ? new short[1] : null; - if (get == null) { - num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter, nonEmptyBlockCount); - } else { - num_palette = createPalette( - layer, - blockToPalette, - paletteToBlock, - blocksCopy, - get, - set, - adapter, - nonEmptyBlockCount - ); - } - // BlockStates - int bitsPerEntry = MathMan.log2nlz(num_palette - 1); - if (Settings.settings().PROTOCOL_SUPPORT_FIX || num_palette != 1) { - bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry - } else { - bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries - } - if (bitsPerEntry > 8) { - bitsPerEntry = MathMan.log2nlz(Block.BLOCK_STATE_REGISTRY.size() - 1); - } - - final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntry); - final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong); - - if (num_palette == 1) { - for (int i = 0; i < blockBitArrayEnd; i++) { - blockStates[i] = 0; - } - } else { - final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntry, 4096, blockStates); - bitArray.fromRaw(blocksCopy); - } - - LevelChunkSection levelChunkSection = newChunkSection(layer); - // set palette & data bits - final PalettedContainer dataPaletteBlocks = - levelChunkSection.getStates(); - // private DataPalette h; - // protected DataBits a; - final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd); - final BitStorage nmsBits = new BitStorage(bitsPerEntry, 4096, bits); - final Palette blockStatePalettedContainer; - if (bitsPerEntry <= 4) { - blockStatePalettedContainer = new LinearPalette<>(Block.BLOCK_STATE_REGISTRY, bitsPerEntry, dataPaletteBlocks, - NbtUtils::readBlockState - ); - } else if (bitsPerEntry < 9) { - blockStatePalettedContainer = new HashMapPalette<>( - Block.BLOCK_STATE_REGISTRY, - bitsPerEntry, - dataPaletteBlocks, - NbtUtils::readBlockState, - NbtUtils::writeBlockState - ); - } else { - blockStatePalettedContainer = LevelChunkSection.GLOBAL_BLOCKSTATE_PALETTE; - } - - // set palette if required - if (bitsPerEntry < 9) { - for (int i = 0; i < num_palette; i++) { - final int ordinal = paletteToBlock[i]; - blockToPalette[ordinal] = Integer.MAX_VALUE; - final BlockState state = BlockTypesCache.states[ordinal]; - final net.minecraft.world.level.block.state.BlockState blockState = ((PaperweightBlockMaterial) state.getMaterial()).getState(); - blockStatePalettedContainer.idFor(blockState); - } - } - try { - fieldStorage.set(dataPaletteBlocks, nmsBits); - fieldPalette.set(dataPaletteBlocks, blockStatePalettedContainer); - fieldBits.set(dataPaletteBlocks, bitsPerEntry); - } catch (final IllegalAccessException e) { - throw new RuntimeException(e); - } - - if (!fastMode) { - levelChunkSection.recalcBlockCounts(); - } else { - try { - fieldNonEmptyBlockCount.set(levelChunkSection, nonEmptyBlockCount[0]); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - return levelChunkSection; - } catch (final Throwable e) { - throw e; - } finally { - Arrays.fill(blockToPalette, Integer.MAX_VALUE); - Arrays.fill(paletteToBlock, Integer.MAX_VALUE); - Arrays.fill(blockStates, 0); - Arrays.fill(blocksCopy, 0); - } - } - - private static LevelChunkSection newChunkSection(int layer) { - return new LevelChunkSection(layer); - } - - public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException { - fieldTickingFluidContent.setShort(section, (short) 0); - fieldTickingBlockCount.setShort(section, (short) 0); - } - - public static Biome[] getBiomeArray(ChunkBiomeContainer chunkBiomeContainer) { - try { - return (Biome[]) fieldBiomes.get(chunkBiomeContainer); - } catch (IllegalAccessException e) { - e.printStackTrace(); - return null; - } - } - - public static BiomeType adapt(Biome biome, LevelAccessor levelAccessor) { - ResourceLocation resourceLocation = levelAccessor.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY).getKey( - biome); - if (resourceLocation == null) { - return levelAccessor.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY).getId(biome) == -1 - ? BiomeTypes.OCEAN - : null; - } - return BiomeTypes.get(resourceLocation.toString().toLowerCase(Locale.ROOT)); - } - - @SuppressWarnings("unchecked") - static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { - try { - // Do the method ourselves to avoid trying to reflect generic method parameters - if (levelChunk.loaded || levelChunk.level.isClientSide()) { - BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos()); - if (blockEntity != null) { - if (!levelChunk.level.isClientSide) { - Block block = beacon.getBlockState().getBlock(); - if (block instanceof EntityBlock) { - GameEventListener gameEventListener = ((EntityBlock) block).getListener(levelChunk.level, beacon); - if (gameEventListener != null) { - int i = SectionPos.blockToSectionCoord(beacon.getBlockPos().getY()); - GameEventDispatcher gameEventDispatcher = levelChunk.getEventDispatcher(i); - gameEventDispatcher.unregister(gameEventListener); - if (gameEventDispatcher.isEmpty()) { - try { - ((Int2ObjectMap) fieldGameEventDispatcherSections.get(levelChunk)) - .remove(i); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - } - } - } - } - fieldRemove.set(beacon, true); - } - } - methodremoveBlockEntityTicker.invoke(levelChunk, beacon.getBlockPos()); - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - } - - static List getEntities(LevelChunk chunk) { - return chunk.level.entityManager.getEntities(chunk.getPos()); - } - - public static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { - boolean isVillager = entity instanceof AbstractVillager && !Fawe.isMainThread(); - boolean unset = false; - if (isVillager) { - try { - if (fieldOffers.get(entity) != null) { - fieldOffers.set(entity, OFFERS); - unset = true; - } - } catch (IllegalAccessException e) { - throw new RuntimeException("Failed to set offers field to villager to avoid async catcher.", e); - } - } - entity.save(compoundTag); - if (unset) { - try { - fieldOffers.set(entity, null); - } catch (IllegalAccessException e) { - throw new RuntimeException("Failed to set offers field to null again on villager.", e); - } - } - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPostProcessor.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPostProcessor.java deleted file mode 100644 index 0833c6ecb..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPostProcessor.java +++ /dev/null @@ -1,175 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; - -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.ProcessorScope; -import com.fastasyncworldedit.core.queue.IBatchProcessor; -import com.fastasyncworldedit.core.queue.IChunk; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.fastasyncworldedit.core.registry.state.PropertyKey; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.Fluids; - -import javax.annotation.Nullable; - -public class PaperweightPostProcessor implements IBatchProcessor { - - @Override - public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) { - return set; - } - - @SuppressWarnings("deprecation") - @Override - public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) { - boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS; - // The PostProcessor shouldn't be added, but just in case - if (!tickFluid) { - return; - } - PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet; - layer: - for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) { - char[] set = iChunkSet.loadIfPresent(layer); - if (set == null) { - // No edit means no need to process - continue; - } - char[] get = null; - for (int i = 0; i < 4096; i++) { - char ordinal = set[i]; - char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__; - boolean fromGet = false; // Used for liquids - if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { - if (get == null) { - get = getBlocks.load(layer); - } - // If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't - // actually being set - if (get == null) { - continue layer; - } - fromGet = true; - ordinal = replacedOrdinal = get[i]; - } - if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { - continue; - } else if (!fromGet) { // if fromGet, don't do the same again - if (get == null) { - get = getBlocks.load(layer); - } - replacedOrdinal = get[i]; - } - boolean ticking = BlockTypesCache.ticking[ordinal]; - boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal]; - boolean replacedWasLiquid = false; - BlockState replacedState = null; - if (!ticking) { - // If the block being replaced was not ticking, it cannot be a liquid - if (!replacedWasTicking) { - continue; - } - // If the block being replaced is not fluid, we do not need to worry - if (!(replacedWasLiquid = - (replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) { - continue; - } - } - BlockState state = BlockState.getFromOrdinal(ordinal); - boolean liquid = state.getMaterial().isLiquid(); - int x = i & 15; - int y = (i >> 8) & 15; - int z = (i >> 4) & 15; - BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z); - if (liquid || replacedWasLiquid) { - if (liquid) { - addFluid(getBlocks.serverLevel, state, position); - continue; - } - // If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this - // may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up - // being ticked anyway. We only need it to be "hit" once. - if (!wasAdjacentToWater(get, set, i, x, y, z)) { - continue; - } - addFluid(getBlocks.serverLevel, replacedState, position); - } - } - } - } - - @Nullable - @Override - public Extent construct(final Extent child) { - throw new UnsupportedOperationException("Processing only"); - } - - @Override - public ProcessorScope getScope() { - return ProcessorScope.READING_SET_BLOCKS; - } - - private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) { - if (set == null || get == null) { - return false; - } - char ordinal; - char reserved = BlockTypesCache.ReservedIDs.__RESERVED__; - if (x > 0 && set[i - 1] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) { - return true; - } - } - if (x < 15 && set[i + 1] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) { - return true; - } - } - if (z > 0 && set[i - 16] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) { - return true; - } - } - if (z < 15 && set[i + 16] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) { - return true; - } - } - if (y > 0 && set[i - 256] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) { - return true; - } - } - if (y < 15 && set[i + 256] != reserved) { - return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal); - } - return false; - } - - @SuppressWarnings("deprecation") - private boolean isFluid(char ordinal) { - return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid(); - } - - @SuppressWarnings("deprecation") - private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) { - Fluid type; - if (replacedState.getBlockType() == BlockTypes.LAVA) { - type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA; - } else { - type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER; - } - serverLevel.getLiquidTicks().scheduleTick( - position, - type, - type.getTickDelay(serverLevel) - ); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighter.java deleted file mode 100644 index ea2afede3..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighter.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; - -import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.queue.IQueueExtent; -import net.minecraft.server.MCUtil; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.server.level.TicketType; -import net.minecraft.util.Unit; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.chunk.ChunkStatus; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; -import java.util.function.IntConsumer; - -public class PaperweightStarlightRelighter extends StarlightRelighter { - - private static final MethodHandle RELIGHT; - private static final TicketType FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); - private static final int LIGHT_LEVEL = MCUtil.getTicketLevelFor(ChunkStatus.LIGHT); - - static { - MethodHandle tmp = null; - try { - MethodHandles.Lookup lookup = MethodHandles.lookup(); - tmp = lookup.findVirtual( - ThreadedLevelLightEngine.class, - "relight", - MethodType.methodType( - int.class, // return type - // params - Set.class, - Consumer.class, - IntConsumer.class - ) - ); - tmp = MethodHandles.dropReturn(tmp); - } catch (NoSuchMethodException | IllegalAccessException e) { - LOGGER.error("Failed to locate 'relight' method in ThreadedLevelLightEngine. Is everything up to date?", e); - } - RELIGHT = tmp; - } - - public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { - super(serverLevel, queue); - } - - @Override - protected ChunkPos createChunkPos(final long chunkKey) { - return new ChunkPos(chunkKey); - } - - @Override - protected long asLong(final int chunkX, final int chunkZ) { - return ChunkPos.asLong(chunkX, chunkZ); - } - - @Override - protected CompletableFuture chunkLoadFuture(final ChunkPos chunkPos) { - return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z) - .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( - FAWE_TICKET, - chunkPos, - LIGHT_LEVEL, - Unit.INSTANCE - )); - } - - public static boolean isUsable() { - return RELIGHT != null; - } - - @Override - protected void invokeRelight( - Set coords, - Consumer chunkCallback, - IntConsumer processCallback - ) { - try { - RELIGHT.invokeExact( - serverLevel.getChunkSource().getLightEngine(), - coords, - chunkCallback, // callback per chunk - processCallback // callback for all chunks - ); - } catch (Throwable throwable) { - LOGGER.error("Error occurred on relighting", throwable); - } - } - - /* - * Allow the server to unload the chunks again. - * Also, if chunk packets are sent delayed, we need to do that here - */ - protected void postProcessChunks(Set coords) { - boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING; - for (ChunkPos pos : coords) { - int x = pos.x; - int z = pos.z; - if (delay) { // we still need to send the block changes of that chunk - PaperweightPlatformAdapter.sendChunk(serverLevel, x, z, false); - } - serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE); - } - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighterFactory.java deleted file mode 100644 index 9cd0a1ef8..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighterFactory.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; - -import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; -import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; -import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; -import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IQueueExtent; -import com.sk89q.worldedit.world.World; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; - -import javax.annotation.Nonnull; - -public class PaperweightStarlightRelighterFactory implements RelighterFactory { - - @Override - public @Nonnull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { - org.bukkit.World w = Bukkit.getWorld(world.getName()); - if (w == null) { - return NullRelighter.INSTANCE; - } - return new PaperweightStarlightRelighter(((CraftWorld) w).getHandle(), queue); - } - -} - diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/nbt/PaperweightLazyCompoundTag.java deleted file mode 100644 index 21bc0fe72..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/nbt/PaperweightLazyCompoundTag.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.nbt; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.LazyCompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import net.minecraft.nbt.NumericTag; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Supplier; - -public class PaperweightLazyCompoundTag extends LazyCompoundTag { - - private final Supplier compoundTagSupplier; - private CompoundTag compoundTag; - - public PaperweightLazyCompoundTag(Supplier compoundTagSupplier) { - super(new HashMap<>()); - this.compoundTagSupplier = compoundTagSupplier; - } - - public PaperweightLazyCompoundTag(net.minecraft.nbt.CompoundTag compoundTag) { - this(() -> compoundTag); - } - - public net.minecraft.nbt.CompoundTag get() { - return compoundTagSupplier.get(); - } - - @Override - @SuppressWarnings("unchecked") - public Map getValue() { - if (compoundTag == null) { - compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); - } - return compoundTag.getValue(); - } - - @Override - public CompoundBinaryTag asBinaryTag() { - getValue(); - return compoundTag.asBinaryTag(); - } - - public boolean containsKey(String key) { - return compoundTagSupplier.get().contains(key); - } - - public byte[] getByteArray(String key) { - return compoundTagSupplier.get().getByteArray(key); - } - - public byte getByte(String key) { - return compoundTagSupplier.get().getByte(key); - } - - public double getDouble(String key) { - return compoundTagSupplier.get().getDouble(key); - } - - public double asDouble(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsDouble(); - } - return 0; - } - - public float getFloat(String key) { - return compoundTagSupplier.get().getFloat(key); - } - - public int[] getIntArray(String key) { - return compoundTagSupplier.get().getIntArray(key); - } - - public int getInt(String key) { - return compoundTagSupplier.get().getInt(key); - } - - public int asInt(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsInt(); - } - return 0; - } - - @SuppressWarnings("unchecked") - public List getList(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof net.minecraft.nbt.ListTag nbtList) { - ArrayList list = new ArrayList<>(); - for (net.minecraft.nbt.Tag elem : nbtList) { - if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { - list.add(new PaperweightLazyCompoundTag(compoundTag)); - } else { - list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem)); - } - } - return list; - } - return Collections.emptyList(); - } - - @SuppressWarnings("unchecked") - public ListTag getListTag(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof net.minecraft.nbt.ListTag) { - return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag); - } - return new ListTag(StringTag.class, Collections.emptyList()); - } - - @SuppressWarnings("unchecked") - public List getList(String key, Class listType) { - ListTag listTag = getListTag(key); - if (listTag.getType().equals(listType)) { - return (List) listTag.getValue(); - } else { - return Collections.emptyList(); - } - } - - public long[] getLongArray(String key) { - return compoundTagSupplier.get().getLongArray(key); - } - - public long getLong(String key) { - return compoundTagSupplier.get().getLong(key); - } - - public long asLong(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsLong(); - } - return 0; - } - - public short getShort(String key) { - return compoundTagSupplier.get().getShort(key); - } - - public String getString(String key) { - return compoundTagSupplier.get().getString(key); - } - - @Override - public String toString() { - return compoundTagSupplier.get().toString(); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java deleted file mode 100644 index 63d93156b..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java +++ /dev/null @@ -1,694 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.regen; - -import com.fastasyncworldedit.bukkit.adapter.Regenerator; -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.queue.IChunkCache; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.util.ReflectionUtils; -import com.fastasyncworldedit.core.util.TaskManager; -import com.google.common.collect.ImmutableList; -import com.mojang.datafixers.util.Either; -import com.mojang.serialization.Codec; -import com.mojang.serialization.Lifecycle; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.PaperweightGetBlocks; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.world.RegenOptions; -import io.papermc.lib.PaperLib; -import net.minecraft.core.MappedRegistry; -import net.minecraft.core.Registry; -import net.minecraft.data.BuiltinRegistries; -import net.minecraft.data.worldgen.biome.Biomes; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.server.level.progress.ChunkProgressListener; -import net.minecraft.util.LinearCongruentialGenerator; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.LevelSettings; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.BiomeSource; -import net.minecraft.world.level.biome.FixedBiomeSource; -import net.minecraft.world.level.biome.OverworldBiomeSource; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkGenerator; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.FlatLevelSource; -import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; -import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; -import net.minecraft.world.level.levelgen.SimpleRandomSource; -import net.minecraft.world.level.levelgen.WorldGenSettings; -import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager; -import net.minecraft.world.level.levelgen.synth.ImprovedNoise; -import net.minecraft.world.level.newbiome.area.Area; -import net.minecraft.world.level.newbiome.area.AreaFactory; -import net.minecraft.world.level.newbiome.context.BigContext; -import net.minecraft.world.level.newbiome.layer.Layer; -import net.minecraft.world.level.newbiome.layer.Layers; -import net.minecraft.world.level.newbiome.layer.traits.PixelTransformer; -import net.minecraft.world.level.storage.LevelStorageSource; -import net.minecraft.world.level.storage.PrimaryLevelData; -import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_17_R1.CraftServer; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator; -import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; - -import javax.annotation.Nullable; -import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.nio.file.Path; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.OptionalLong; -import java.util.Random; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.BooleanSupplier; -import java.util.function.LongFunction; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -public class PaperweightRegen extends Regenerator { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private static final Field worldsField; - private static final Field paperConfigField; - private static final Field generateFlatBedrockField; - private static final Field generatorSettingFlatField; - private static final Field generatorSettingBaseSupplierField; - private static final Field delegateField; - private static final Field chunkSourceField; - - //list of chunk stati in correct order without FULL - private static final Map chunkStati = new LinkedHashMap<>(); - - static { - chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing - chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps - chunkStati.put( - ChunkStatus.STRUCTURE_REFERENCES, - Concurrency.FULL - ); // structure refs: radius 8, but only writes to current chunk - chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // biomes: radius 0 - chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8 - chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE - chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results - chunkStati.put( - ChunkStatus.LIQUID_CARVERS, - Concurrency.NONE - ); // liquid carvers: radius 0, but RADIUS and FULL change results - chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps - chunkStati.put( - ChunkStatus.LIGHT, - Concurrency.FULL - ); // light: radius 1, but no writes to other chunks, only current chunk - chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0 - chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0 - - try { - worldsField = CraftServer.class.getDeclaredField("worlds"); - worldsField.setAccessible(true); - - Field tmpPaperConfigField; - Field tmpFlatBedrockField; - try { //only present on paper - tmpPaperConfigField = Level.class.getDeclaredField("paperConfig"); - tmpPaperConfigField.setAccessible(true); - - tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock"); - tmpFlatBedrockField.setAccessible(true); - } catch (Exception e) { - tmpPaperConfigField = null; - tmpFlatBedrockField = null; - } - paperConfigField = tmpPaperConfigField; - generateFlatBedrockField = tmpFlatBedrockField; - - generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName( - "settings", "g")); - generatorSettingBaseSupplierField.setAccessible(true); - - generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "e")); - generatorSettingFlatField.setAccessible(true); - - delegateField = CustomChunkGenerator.class.getDeclaredField("delegate"); - delegateField.setAccessible(true); - - chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "C")); - chunkSourceField.setAccessible(true); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - //runtime - private ServerLevel originalServerWorld; - private ServerChunkCache originalChunkProvider; - private ServerLevel freshWorld; - private ServerChunkCache freshChunkProvider; - private LevelStorageSource.LevelStorageAccess session; - private StructureManager structureManager; - private ThreadedLevelLightEngine threadedLevelLightEngine; - private ChunkGenerator chunkGenerator; - - private Path tempDir; - - private boolean generateFlatBedrock = false; - - public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) { - super(originalBukkitWorld, region, target, options); - } - - @Override - protected boolean prepare() { - this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle(); - originalChunkProvider = originalServerWorld.getChunkSource(); - - //flat bedrock? (only on paper) - if (paperConfigField != null) { - try { - generateFlatBedrock = generateFlatBedrockField.getBoolean(paperConfigField.get(originalServerWorld)); - } catch (Exception ignored) { - } - } - - seed = options.getSeed().orElse(originalServerWorld.getSeed()); - chunkStati.forEach((s, c) -> super.chunkStatuses.put(new ChunkStatusWrap(s), c)); - - return true; - } - - @Override - protected boolean initNewWorld() throws Exception { - //world folder - tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen"); - - //prepare for world init (see upstream implementation for reference) - org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment(); - org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator(); - LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir); - ResourceKey levelStemResourceKey = getWorldDimKey(environment); - session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey); - PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData; - - BiomeProvider biomeProvider = getBiomeProvider(); - - MinecraftServer server = originalServerWorld.getCraftServer().getServer(); - WorldGenSettings originalOpts = originalWorldData.worldGenSettings(); - WorldGenSettings newOpts = options.getSeed().isPresent() - ? originalOpts.withSeed(originalWorldData.isHardcore(), OptionalLong.of(seed)) - : originalOpts; - LevelSettings newWorldSettings = new LevelSettings( - "faweregentempworld", - originalWorldData.settings.gameType(), - originalWorldData.settings.hardcore(), - originalWorldData.settings.difficulty(), - originalWorldData.settings.allowCommands(), - originalWorldData.settings.gameRules(), - originalWorldData.settings.getDataPackConfig() - ); - PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, Lifecycle.stable()); - - //init world - freshWorld = Fawe.instance().getQueueHandler().sync((Supplier) () -> new ServerLevel( - server, - server.executor, - session, - newWorldData, - originalServerWorld.dimension(), - originalServerWorld.dimensionType(), - new RegenNoOpWorldLoadListener(), - // placeholder. Required for new ChunkProviderServer, but we create and then set it later - newOpts.dimensions().get(levelStemResourceKey).generator(), - originalServerWorld.isDebug(), - seed, - ImmutableList.of(), - false, - environment, - generator, - biomeProvider - ) { - private final Biome singleBiome = options.hasBiomeType() ? BuiltinRegistries.BIOME.get(ResourceLocation.tryParse( - options - .getBiomeType() - .getId())) : null; - - @Override - public void tick(BooleanSupplier shouldKeepTicking) { //no ticking - } - - @Override - public Biome getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { - if (options.hasBiomeType()) { - return singleBiome; - } - return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome(biomeX, biomeY, biomeZ); - } - }).get(); - freshWorld.noSave = true; - removeWorldFromWorldsMap(); - newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name - if (paperConfigField != null) { - paperConfigField.set(freshWorld, originalServerWorld.paperConfig); - } - - //generator - if (originalChunkProvider.getGenerator() instanceof FlatLevelSource) { - FlatLevelGeneratorSettings generatorSettingFlat = (FlatLevelGeneratorSettings) generatorSettingFlatField.get( - originalChunkProvider.getGenerator()); - chunkGenerator = new FlatLevelSource(generatorSettingFlat); - } else if (originalChunkProvider.getGenerator() instanceof NoiseBasedChunkGenerator) { - Supplier generatorSettingBaseSupplier = (Supplier) generatorSettingBaseSupplierField - .get(originalChunkProvider.getGenerator()); - BiomeSource biomeSource; - if (options.hasBiomeType()) { - biomeSource = new FixedBiomeSource(BuiltinRegistries.BIOME.get(ResourceLocation.tryParse(options - .getBiomeType() - .getId()))); - } else { - biomeSource = originalChunkProvider.getGenerator().getBiomeSource(); - if (biomeSource instanceof OverworldBiomeSource) { - biomeSource = fastOverworldBiomeSource(biomeSource); - } - } - chunkGenerator = new NoiseBasedChunkGenerator(biomeSource, seed, generatorSettingBaseSupplier); - } else if (originalChunkProvider.getGenerator() instanceof CustomChunkGenerator) { - chunkGenerator = (ChunkGenerator) delegateField.get(originalChunkProvider.getGenerator()); - } else { - LOGGER.error("Unsupported generator type {}", originalChunkProvider.getGenerator().getClass().getName()); - return false; - } - if (generator != null) { - chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator); - generateConcurrent = generator.isParallelCapable(); - } - - freshChunkProvider = new ServerChunkCache( - freshWorld, - session, - server.getFixerUpper(), - server.getStructureManager(), - server.executor, - chunkGenerator, - freshWorld.spigotConfig.viewDistance, - server.forceSynchronousWrites(), - new RegenNoOpWorldLoadListener(), - (chunkCoordIntPair, state) -> { - }, - () -> server.overworld().getDataStorage() - ) { - // redirect to LevelChunks created in #createChunks - @Override - public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean create) { - ChunkAccess chunkAccess = getChunkAt(x, z); - if (chunkAccess == null && create) { - chunkAccess = createChunk(getProtoChunkAt(x, z)); - } - return chunkAccess; - } - }; - - chunkSourceField.set(freshWorld, freshChunkProvider); - //let's start then - structureManager = server.getStructureManager(); - threadedLevelLightEngine = freshChunkProvider.getLightEngine(); - - return true; - } - - @Override - protected void cleanup() { - try { - session.close(); - } catch (Exception ignored) { - } - - //shutdown chunk provider - try { - Fawe.instance().getQueueHandler().sync(() -> { - try { - freshChunkProvider.close(false); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - } catch (Exception ignored) { - } - - //remove world from server - try { - Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap); - } catch (Exception ignored) { - } - - //delete directory - try { - SafeFiles.tryHardToDeleteDir(tempDir); - } catch (Exception ignored) { - } - } - - @Override - protected ProtoChunk createProtoChunk(int x, int z) { - return PaperLib.isPaper() - ? new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld, freshWorld) // paper - : new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld); // spigot - } - - @Override - protected LevelChunk createChunk(ProtoChunk protoChunk) { - return new LevelChunk( - freshWorld, - protoChunk, - null // we don't want to add entities - ); - } - - @Override - protected ChunkStatusWrap getFullChunkStatus() { - return new ChunkStatusWrap(ChunkStatus.FULL); - } - - @Override - protected List getBlockPopulators() { - return originalServerWorld.getWorld().getPopulators(); - } - - @Override - protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) { - // BlockPopulator#populate has to be called synchronously for TileEntity access - TaskManager.taskManager().task(() -> blockPopulator.populate(freshWorld.getWorld(), random, levelChunk.getBukkitChunk())); - } - - @Override - protected IChunkCache initSourceQueueCache() { - return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) { - @Override - public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) { - return getChunkAt(x, z); - } - }; - } - - //util - @SuppressWarnings("unchecked") - private void removeWorldFromWorldsMap() { - Fawe.instance().getQueueHandler().sync(() -> { - try { - Map map = (Map) worldsField.get(Bukkit.getServer()); - map.remove("faweregentempworld"); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - }); - } - - private ResourceKey getWorldDimKey(org.bukkit.World.Environment env) { - return switch (env) { - case NETHER -> LevelStem.NETHER; - case THE_END -> LevelStem.END; - default -> LevelStem.OVERWORLD; - }; - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private BiomeSource fastOverworldBiomeSource(BiomeSource biomeSource) throws Exception { - Field legacyBiomeInitLayerField = OverworldBiomeSource.class.getDeclaredField( - Refraction.pickName("legacyBiomeInitLayer", "i")); - legacyBiomeInitLayerField.setAccessible(true); - Field largeBiomesField = OverworldBiomeSource.class.getDeclaredField(Refraction.pickName("largeBiomes", "j")); - largeBiomesField.setAccessible(true); - Field biomeRegistryField = OverworldBiomeSource.class.getDeclaredField(Refraction.pickName("biomes", "k")); - biomeRegistryField.setAccessible(true); - Field areaLazyField = Layer.class.getDeclaredField(Refraction.pickName("area", "b")); - areaLazyField.setAccessible(true); - Method initAreaFactoryMethod = Layers.class.getDeclaredMethod( - Refraction.pickName("getDefaultLayer", "a"), - boolean.class, - int.class, - int.class, - LongFunction.class - ); - initAreaFactoryMethod.setAccessible(true); - - //init new WorldChunkManagerOverworld - boolean legacyBiomeInitLayer = legacyBiomeInitLayerField.getBoolean(biomeSource); - boolean largebiomes = largeBiomesField.getBoolean(biomeSource); - Registry biomeRegistryMojang = (Registry) biomeRegistryField.get(biomeSource); - Registry biomeRegistry; - if (options.hasBiomeType()) { - Biome biome = BuiltinRegistries.BIOME.get(ResourceLocation.tryParse(options.getBiomeType().getId())); - biomeRegistry = new MappedRegistry<>( - ResourceKey.createRegistryKey(new ResourceLocation("fawe_biomes")), - Lifecycle.experimental() - ); - ((MappedRegistry) biomeRegistry).registerMapping(0, BuiltinRegistries.BIOME.getResourceKey(biome).get(), biome, - Lifecycle.experimental() - ); - } else { - biomeRegistry = biomeRegistryMojang; - } - - //replace genLayer - AreaFactory factory = (AreaFactory) initAreaFactoryMethod.invoke( - null, - legacyBiomeInitLayer, - largebiomes ? 6 : 4, - 4, - (LongFunction) (salt -> new FastWorldGenContextArea(seed, salt)) - ); - biomeSource = new FastOverworldBiomeSource(biomeRegistry, new FastGenLayer(factory)); - - return biomeSource; - } - - private static class FastOverworldBiomeSource extends BiomeSource { - - private final Registry biomeRegistry; - private final boolean isSingleRegistry; - private final FastGenLayer fastGenLayer; - - public FastOverworldBiomeSource( - Registry biomeRegistry, - FastGenLayer genLayer - ) { - super(biomeRegistry.stream().collect(Collectors.toList())); - this.biomeRegistry = biomeRegistry; - this.isSingleRegistry = biomeRegistry.entrySet().size() == 1; - this.fastGenLayer = genLayer; - } - - @Override - protected Codec codec() { - return OverworldBiomeSource.CODEC; - } - - @Override - public BiomeSource withSeed(final long seed) { - return null; - } - - @Override - public Biome getNoiseBiome(int biomeX, int biomeY, int biomeZ) { - if (this.isSingleRegistry) { - return this.biomeRegistry.byId(0); - } - return this.fastGenLayer.get(this.biomeRegistry, biomeX, biomeZ); - } - - } - - private static class FastWorldGenContextArea implements BigContext { - - private final ConcurrentHashMap sharedAreaMap = new ConcurrentHashMap<>(); - private final ImprovedNoise improvedNoise; - private final long magicrandom; - private final ConcurrentHashMap map = new ConcurrentHashMap<>(); //needed for multithreaded generation - - public FastWorldGenContextArea(long seed, long lconst) { - this.magicrandom = mix(seed, lconst); - this.improvedNoise = new ImprovedNoise(new SimpleRandomSource(seed)); - } - - private static long mix(long seed, long salt) { - long l = LinearCongruentialGenerator.next(salt, salt); - l = LinearCongruentialGenerator.next(l, salt); - l = LinearCongruentialGenerator.next(l, salt); - long m = LinearCongruentialGenerator.next(seed, l); - m = LinearCongruentialGenerator.next(m, l); - m = LinearCongruentialGenerator.next(m, l); - return m; - } - - @Override - public FastAreaLazy createResult(PixelTransformer pixelTransformer) { - return new FastAreaLazy(sharedAreaMap, pixelTransformer); - } - - @Override - public void initRandom(long x, long z) { - long l = this.magicrandom; - l = LinearCongruentialGenerator.next(l, x); - l = LinearCongruentialGenerator.next(l, z); - l = LinearCongruentialGenerator.next(l, x); - l = LinearCongruentialGenerator.next(l, z); - this.map.put(Thread.currentThread().getId(), l); - } - - @Override - public int nextRandom(int y) { - long tid = Thread.currentThread().getId(); - long e = this.map.computeIfAbsent(tid, i -> 0L); - int mod = (int) Math.floorMod(e >> 24L, (long) y); - this.map.put(tid, LinearCongruentialGenerator.next(e, this.magicrandom)); - return mod; - } - - @Override - public ImprovedNoise getBiomeNoise() { - return this.improvedNoise; - } - - } - - private static class FastGenLayer extends Layer { - - private final FastAreaLazy fastAreaLazy; - - public FastGenLayer(AreaFactory factory) { - super(() -> null); - this.fastAreaLazy = factory.make(); - } - - @Override - public Biome get(Registry registry, int x, int z) { - ResourceKey key = Biomes.byId(this.fastAreaLazy.get(x, z)); - if (key == null) { - return registry.get(Biomes.byId(0)); - } - Biome biome = registry.get(key); - if (biome == null) { - return registry.get(Biomes.byId(0)); - } - return biome; - } - - } - - private record FastAreaLazy(ConcurrentHashMap sharedMap, PixelTransformer transformer) implements Area { - - @Override - public int get(int x, int z) { - long zx = ChunkPos.asLong(x, z); - return this.sharedMap.computeIfAbsent(zx, i -> this.transformer.apply(x, z)); - } - - } - - private static class RegenNoOpWorldLoadListener implements ChunkProgressListener { - - private RegenNoOpWorldLoadListener() { - } - - @Override - public void updateSpawnPos(ChunkPos spawnPos) { - } - - @Override - public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) { - } - - @Override - public void start() { - - } - - @Override - public void stop() { - } - - // TODO Paper only(?) @Override - public void setChunkRadius(int radius) { - } - - } - - private class FastProtoChunk extends ProtoChunk { - - // avoid warning on paper - public FastProtoChunk(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor world, ServerLevel serverLevel) { - super(pos, upgradeData, world, serverLevel); - } - - // compatibility with spigot - public FastProtoChunk(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor levelHeightAccessor) { - super(pos, upgradeData, levelHeightAccessor); - } - - public boolean generateFlatBedrock() { - return generateFlatBedrock; - } - - // no one will ever see the entities! - @Override - public List getEntities() { - return Collections.emptyList(); - } - - } - - protected class ChunkStatusWrap extends ChunkStatusWrapper { - - private final ChunkStatus chunkStatus; - - public ChunkStatusWrap(ChunkStatus chunkStatus) { - this.chunkStatus = chunkStatus; - } - - @Override - public int requiredNeighborChunkRadius() { - return chunkStatus.getRange(); - } - - @Override - public String name() { - return chunkStatus.getName(); - } - - @Override - public CompletableFuture processChunk(List accessibleChunks) { - return chunkStatus.generate( - Runnable::run, // TODO revisit, we might profit from this somehow? - freshWorld, - chunkGenerator, - structureManager, - threadedLevelLightEngine, - c -> CompletableFuture.completedFuture(Either.left(c)), - accessibleChunks - ); - } - - } - -} diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index 1a922b7af..e02685954 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -210,7 +210,7 @@ tasks { versionNumber.set("${project.version}") versionType.set("release") uploadFile.set(file("build/libs/${rootProject.name}-Bukkit-${project.version}.jar")) - gameVersions.addAll(listOf("1.20.4", "1.20.3", "1.20.2", "1.20.1", "1.20", "1.19.4", "1.18.2", "1.17.1")) + gameVersions.addAll(listOf("1.20.4", "1.20.3", "1.20.2", "1.20.1", "1.20", "1.19.4", "1.18.2")) loaders.addAll(listOf("paper", "spigot")) changelog.set("The changelog is available on GitHub: https://github.com/IntellectualSites/" + "FastAsyncWorldEdit/releases/tag/${project.version}") 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 d35ea9a28..3bf09481e 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 @@ -307,9 +307,6 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser if (!tickFluid) { return null; } - if (Settings.settings().QUEUE.NO_TICK_FASTMODE && fastMode) { - return null; - } return this.plugin.getBukkitImplAdapter().getTickingPostProcessor(); } //FAWE end diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index 009958270..89f48b697 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -511,7 +511,7 @@ public class Settings extends Config { " - A larger value will use slightly less CPU time", " - A smaller value will reduce memory usage", " - A value too small may break some operations (deform?)", - " - Values smaller than the configurated parallel-threads are not accepted", + " - Values smaller than the configured parallel-threads are not accepted", " - It is recommended this option be at least 4x greater than parallel-threads" }) @@ -544,12 +544,6 @@ public class Settings extends Config { }) public boolean POOL = true; - @Comment({ - "When using fastmode do not bother to tick existing/placed blocks/fluids", - "Only works in versions up to 1.17.1" - }) - public boolean NO_TICK_FASTMODE = true; - public static class PROGRESS { @Comment({"Display constant titles about the progress of a user's edit", From 2d0a3e6081967bb677afffbc03ba39f67745280d Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 17 Mar 2024 13:15:28 +0100 Subject: [PATCH 158/466] fix: do not error when attempting to parse "|" as a pattern (#2625) --- .../extension/factory/parser/DefaultBlockParser.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 0e70a18a6..969216896 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 @@ -64,6 +64,7 @@ import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; +import javax.annotation.Nonnull; import java.util.Arrays; import java.util.HashMap; import java.util.Locale; @@ -337,9 +338,10 @@ public class DefaultBlockParser extends InputParser { return SuggestionHelper.getBlockPropertySuggestions(blockType, props); } + @Nonnull private BaseBlock parseLogic(String input, ParserContext context) throws InputParseException { //FAWE start - String[] blockAndExtraData = input.trim().split("\\|"); + String[] blockAndExtraData = input.trim().split("(?, Object> blockStates = new HashMap<>(); //FAWE end From 2d0ea9adf8832684d2bb7c73e42cc87dc9c03a7f Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 17 Mar 2024 13:16:10 +0100 Subject: [PATCH 159/466] Reword tree type message (#2628) Signed-off-by: Alexander Brandes --- .../main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index a9ba45afe..1598cb547 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 @@ -327,12 +327,12 @@ public class BukkitWorld extends AbstractWorld { treeTypeMapping.put(TreeGenerator.TreeType.RANDOM_MUSHROOM, TreeType.BROWN_MUSHROOM); for (TreeGenerator.TreeType type : TreeGenerator.TreeType.values()) { if (treeTypeMapping.get(type) == null) { - LOGGER.error("No TreeType mapping for TreeGenerator.TreeType." + type); //FAWE start + LOGGER.info("No TreeType mapping for TreeGenerator.TreeType." + type); LOGGER.info("The above message is displayed because your FAWE version is newer than {}" + " and contains features of future minecraft versions which do not exist in {} hence the tree type" + - "{} is not available. This is not an error. This version will work on your version of Minecraft." + - "This is an informative message only.", Bukkit.getVersion(), Bukkit.getVersion(), type); + " {} is not available. This is not an error. This version of FAWE will work on your version of " + + " Minecraft. This is an informative message only.", Bukkit.getVersion(), Bukkit.getVersion(), type); //FAWE end } } From dc61efe11ccf4c41a3bc0c791fea06780884019d Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sun, 17 Mar 2024 13:17:00 +0100 Subject: [PATCH 160/466] Implement linear patterns using RandomPattern + SimpleRandom (#2630) --- .../parser/pattern/Linear2DPatternParser.java | 8 +-- .../parser/pattern/Linear3DPatternParser.java | 8 +-- .../pattern/Linear2DBlockPattern.java | 5 ++ .../pattern/Linear3DBlockPattern.java | 5 ++ .../core/math/random/Linear2DRandom.java | 50 ++++++++++++++++ .../core/math/random/Linear3DRandom.java | 58 +++++++++++++++++++ .../core/math/random/SimpleRandom.java | 18 +++++- .../collection/SimpleRandomCollection.java | 2 +- 8 files changed, 141 insertions(+), 13 deletions(-) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear2DRandom.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear3DRandom.java diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear2DPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear2DPatternParser.java index 5a310f60a..7da0b2377 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear2DPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear2DPatternParser.java @@ -2,7 +2,7 @@ package com.fastasyncworldedit.core.extension.factory.parser.pattern; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.extension.factory.parser.RichParser; -import com.fastasyncworldedit.core.function.pattern.Linear2DBlockPattern; +import com.fastasyncworldedit.core.math.random.Linear2DRandom; import com.google.common.base.Preconditions; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.util.SuggestionHelper; @@ -14,7 +14,6 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nonnull; -import java.util.Set; import java.util.stream.Stream; public class Linear2DPatternParser extends RichParser { @@ -59,9 +58,8 @@ public class Linear2DPatternParser extends RichParser { zScale = Integer.parseInt(arguments[2]); Preconditions.checkArgument(zScale != 0); } - if (inner instanceof RandomPattern) { - Set patterns = ((RandomPattern) inner).getPatterns(); - return new Linear2DBlockPattern(patterns.toArray(new Pattern[0]), xScale, zScale); + if (inner instanceof RandomPattern rp) { + return new RandomPattern(new Linear2DRandom(xScale, zScale), rp); } throw new InputParseException(TextComponent.of("Pattern " + inner.getClass().getSimpleName() + " cannot be used with " + getPrefix())); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear3DPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear3DPatternParser.java index ef45e8faa..cd3a7d8db 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear3DPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear3DPatternParser.java @@ -2,7 +2,7 @@ package com.fastasyncworldedit.core.extension.factory.parser.pattern; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.extension.factory.parser.RichParser; -import com.fastasyncworldedit.core.function.pattern.Linear3DBlockPattern; +import com.fastasyncworldedit.core.math.random.Linear3DRandom; import com.google.common.base.Preconditions; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.util.SuggestionHelper; @@ -14,7 +14,6 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nonnull; -import java.util.Set; import java.util.stream.Stream; public class Linear3DPatternParser extends RichParser { @@ -64,9 +63,8 @@ public class Linear3DPatternParser extends RichParser { zScale = Integer.parseInt(arguments[3]); Preconditions.checkArgument(zScale != 0); } - if (inner instanceof RandomPattern) { - Set patterns = ((RandomPattern) inner).getPatterns(); - return new Linear3DBlockPattern(patterns.toArray(new Pattern[0]), xScale, yScale, zScale); + if (inner instanceof RandomPattern rp) { + return new RandomPattern(new Linear3DRandom(xScale, yScale, zScale), rp); } throw new InputParseException(TextComponent.of("Pattern " + inner.getClass().getSimpleName() + " cannot be used with " + getPrefix())); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java index 7c923c4d4..523f22541 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java @@ -9,6 +9,11 @@ import com.sk89q.worldedit.world.block.BaseBlock; import static java.lang.Math.floorDiv; +/** + * @deprecated replaced by {@link com.sk89q.worldedit.function.pattern.RandomPattern} + * combined with {@link com.fastasyncworldedit.core.math.random.Linear2DRandom}. + */ +@Deprecated(forRemoval = true, since = "TODO") public class Linear2DBlockPattern extends AbstractPattern { private final Pattern[] patternsArray; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java index 04028244d..ea2e37588 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java @@ -9,6 +9,11 @@ import com.sk89q.worldedit.world.block.BaseBlock; import static java.lang.Math.floorDiv; +/** + * @deprecated replaced by {@link com.sk89q.worldedit.function.pattern.RandomPattern} + * combined with {@link com.fastasyncworldedit.core.math.random.Linear3DRandom}. + */ +@Deprecated(forRemoval = true, since = "TODO") public class Linear3DBlockPattern extends AbstractPattern { private final Pattern[] patternsArray; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear2DRandom.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear2DRandom.java new file mode 100644 index 000000000..4f039031e --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear2DRandom.java @@ -0,0 +1,50 @@ +package com.fastasyncworldedit.core.math.random; + +import static com.fastasyncworldedit.core.math.random.Linear3DRandom.doubleDiv; +import static java.lang.Math.floorDiv; + +/** + * A {@link SimpleRandom} that deterministically maps coordinates + * to values. + * @since TODO + */ +public class Linear2DRandom implements SimpleRandom { + private final int xScale; + private final int zScale; + + /** + * Creates a new {@link Linear2DRandom} instance + * + * @param xScale the scale applied to the x component of a coordinate + * @param zScale the scale applied to the z component of a coordinate + */ + public Linear2DRandom(final int xScale, final int zScale) { + this.xScale = xScale; + this.zScale = zScale; + } + + @Override + public double nextDouble(final int x, final int y, final int z) { + return nextDouble(x, y, z, 1d); + } + + @Override + public double nextDouble(final int x, final int y, final int z, double bound) { + double index = (doubleDiv(x, this.xScale) + doubleDiv(z, this.zScale)) % bound; + if (index < 0) { + index += bound; + } + return index; + + } + + @Override + public int nextInt(final int x, final int y, final int z, final int bound) { + int index = (floorDiv(x, this.xScale) + floorDiv(z, this.zScale)) % bound; + if (index < 0) { + index += bound; + } + return index; + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear3DRandom.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear3DRandom.java new file mode 100644 index 000000000..87f350fe4 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear3DRandom.java @@ -0,0 +1,58 @@ +package com.fastasyncworldedit.core.math.random; + +import static java.lang.Math.floorDiv; + +/** + * A {@link SimpleRandom} that deterministically maps coordinates + * to values. + * @since TODO + */ +public class Linear3DRandom implements SimpleRandom { + + private final int xScale; + private final int yScale; + private final int zScale; + + /** + * Creates a new {@link Linear3DRandom} instance + * + * @param xScale the scale applied to the x component of a coordinate + * @param yScale the scale applied to the y component of a coordinate + * @param zScale the scale applied to the z component of a coordinate + */ + public Linear3DRandom(final int xScale, final int yScale, final int zScale) { + this.xScale = xScale; + this.yScale = yScale; + this.zScale = zScale; + } + + @Override + public double nextDouble(final int x, final int y, final int z) { + return nextDouble(x, y, z, 1d); + } + + @Override + public double nextDouble(final int x, final int y, final int z, double bound) { + double index = (doubleDiv(x, this.xScale) + doubleDiv(y, this.yScale) + doubleDiv(z, this.zScale)) % bound; + if (index < 0) { + index += bound; + } + return index; + } + + // used to avoid explicit conversion at call site + static double doubleDiv(double dividend, double divisor) { + // add a minimal value to avoid too many integral values hitting the exact weight of an entry in SimpleRandomCollection + return Math.nextUp(dividend) / divisor; + } + + @Override + public int nextInt(final int x, final int y, final int z, final int bound) { + int index = (floorDiv(x, this.xScale) + floorDiv(y, this.yScale) + floorDiv(z, this.zScale)) % bound; + if (index < 0) { + index += bound; + } + return index; + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/SimpleRandom.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/SimpleRandom.java index e38214936..8b22b66a2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/SimpleRandom.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/SimpleRandom.java @@ -13,6 +13,20 @@ public interface SimpleRandom { */ double nextDouble(int x, int y, int z); + /** + * Generate a random double from three integer components. + * The generated value is between 0 (inclusive) and {@code bound} (exclusive). + * + * @param x the first component + * @param y the second component + * @param z the third component + * @param bound upper bound (exclusive) + * @return a double between 0 (inclusive) and {@code bound} (exclusive) + */ + default double nextDouble(int x, int y, int z, double bound) { + return nextDouble(x, y, z) * bound; + } + /** * Generate a random integer from three integer components. * The generated value is between 0 (inclusive) and 1 (exclusive) @@ -24,8 +38,8 @@ public interface SimpleRandom { * @return a random integer between 0 (inclusive) and {@code bound} (exclusive) */ default int nextInt(int x, int y, int z, int bound) { - double val = nextDouble(x, y, z); - return (int) (val * bound); + double val = nextDouble(x, y, z, bound); + return (int) val; } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/SimpleRandomCollection.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/SimpleRandomCollection.java index dc2107559..5b7dca98f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/SimpleRandomCollection.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/SimpleRandomCollection.java @@ -36,7 +36,7 @@ public class SimpleRandomCollection extends RandomCollection { @Override public E next(int x, int y, int z) { - return map.ceilingEntry(getRandom().nextDouble(x, y, z) * this.total).getValue(); + return map.ceilingEntry(getRandom().nextDouble(x, y, z, this.total)).getValue(); } } From d2ca3ed6fe8ca58ca31a441a3ebecdc943f4431f Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 17 Mar 2024 20:25:09 +0100 Subject: [PATCH 161/466] fix: better image reading errors (#2632) - closes #2593 --- .../core/command/tool/brush/HeightBrush.java | 2 +- .../core/util/MainUtil.java | 21 +++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/HeightBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/HeightBrush.java index fea4884f1..2c6ea5ec0 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/HeightBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/HeightBrush.java @@ -53,7 +53,7 @@ public class HeightBrush implements Brush { try { heightMap = ScalableHeightMap.fromPNG(stream); } catch (IOException e) { - throw new FaweException(Caption.of("fawe.worldedit.brush.brush.height.invalid")); + throw new FaweException(Caption.of("fawe.worldedit.brush.brush.height.invalid", e.getMessage())); } } else if (clipboard != null) { heightMap = ScalableHeightMap.fromClipboard(clipboard, minY, maxY); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java index 8122a840c..cbe9c6897 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java @@ -38,6 +38,8 @@ import org.apache.logging.log4j.Logger; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.imageio.ImageIO; +import javax.imageio.ImageReadParam; +import javax.imageio.ImageReader; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; @@ -70,6 +72,7 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; @@ -519,8 +522,22 @@ public class MainUtil { return destFile; } - public static BufferedImage readImage(InputStream in) throws IOException { - return MainUtil.toRGB(ImageIO.read(in)); + public static BufferedImage readImage(InputStream stream) throws IOException { + Iterator iter = ImageIO.getImageReaders(stream); + if (!iter.hasNext()) { + throw new IOException("Could not get image reader from stream."); + } + ImageReader reader = iter.next(); + ImageReadParam param = reader.getDefaultReadParam(); + reader.setInput(stream, true, true); + BufferedImage bi; + try { + bi = reader.read(0, param); + } finally { + reader.dispose(); + stream.close(); + } + return MainUtil.toRGB(bi); } public static BufferedImage readImage(URL url) throws IOException { From b93f01c5b30871ddf0a8ca6e26a8d525280bad9a Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Sun, 17 Mar 2024 20:25:29 +0100 Subject: [PATCH 162/466] Update paperweight 1.20.4 - isOpaque does not exist (anymore) (#2629) * chore/fix: update paperweight 1.20.4 - isOpaque does not exist (anymore) * chore: update paperweight yet again (i feel scammed) * chore: missing invert of canOcclude in isTranslucent --- .../adapters/adapter-1_20_4/build.gradle.kts | 2 +- .../v1_20_R3/PaperweightBlockMaterial.java | 22 +++++-------------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 02f5a3c53..f18ef582f 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240106.182028-62") + the().paperDevBundle("1.20.4-R0.1-20240316.193646-135") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java index edbe268fe..74b1c035c 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java @@ -2,18 +2,15 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; import com.google.common.base.Suppliers; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.util.ReflectionUtil; -import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.world.registry.BlockMaterial; import net.minecraft.core.BlockPos; import net.minecraft.world.level.EmptyBlockGetter; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock; -import net.minecraft.world.level.block.LiquidBlock; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.material.PushReaction; import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; @@ -21,7 +18,6 @@ public class PaperweightBlockMaterial implements BlockMaterial { private final Block block; private final BlockState blockState; - private final boolean isTranslucent; private final CraftBlockData craftBlockData; private final org.bukkit.Material craftMaterial; private final int opacity; @@ -36,11 +32,6 @@ public class PaperweightBlockMaterial implements BlockMaterial { this.blockState = blockState; this.craftBlockData = CraftBlockData.fromData(blockState); this.craftMaterial = craftBlockData.getMaterial(); - BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, - Refraction.pickName("properties", "aP")); - this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo, - Refraction.pickName("canOcclude", "n") - ); opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity( BlockPos.ZERO, @@ -75,7 +66,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isOpaque() { - return blockState.isOpaque(); + return blockState.canOcclude(); } @Override @@ -85,14 +76,13 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isLiquid() { - // TODO: Better check ? - return block instanceof LiquidBlock; + return !blockState.getFluidState().is(Fluids.EMPTY); } @Override public boolean isSolid() { - // TODO: Replace - return blockState.isSolid(); + // No access to world -> EmptyBlockGetter + return blockState.isSolidRender(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); } @Override @@ -158,7 +148,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isTranslucent() { - return isTranslucent; + return !blockState.canOcclude(); } @Override From b512182e1f6e417501236abab56d6b39a6080229 Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 17 Mar 2024 20:25:43 +0100 Subject: [PATCH 163/466] feat: save region selector to session store (#2621) * feat: save region selector to session store - closes #2397 * Move new gson adapters to FAWE packages --- .../core}/util/gson/ItemTypeAdapter.java | 2 +- .../core/util/gson/RegionSelectorAdapter.java | 33 +++++++++++++++++ .../com/sk89q/worldedit/LocalSession.java | 5 ++- .../worldedit/command/SelectionCommands.java | 8 +---- .../regions/selector/RegionSelectorType.java | 35 ++++++++++++++++++- .../sk89q/worldedit/util/gson/GsonUtil.java | 7 +++- 6 files changed, 79 insertions(+), 11 deletions(-) rename worldedit-core/src/main/java/com/{sk89q/worldedit => fastasyncworldedit/core}/util/gson/ItemTypeAdapter.java (94%) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/RegionSelectorAdapter.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/ItemTypeAdapter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/ItemTypeAdapter.java similarity index 94% rename from worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/ItemTypeAdapter.java rename to worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/ItemTypeAdapter.java index 5f8d6d9a2..fe684fb8c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/ItemTypeAdapter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/ItemTypeAdapter.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.util.gson; +package com.fastasyncworldedit.core.util.gson; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/RegionSelectorAdapter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/RegionSelectorAdapter.java new file mode 100644 index 000000000..d817185ee --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/RegionSelectorAdapter.java @@ -0,0 +1,33 @@ +package com.fastasyncworldedit.core.util.gson; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.RegionSelectorType; + +import java.lang.reflect.Type; + +public class RegionSelectorAdapter implements JsonDeserializer, JsonSerializer { + + @Override + public RegionSelector deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException { + RegionSelectorType regionType = RegionSelectorType.valueOf(json.getAsString()); + return regionType.createSelector(); + } + + @Override + public JsonElement serialize(RegionSelector selector, Type type, JsonSerializationContext context) { + RegionSelectorType regionType = RegionSelectorType.getForSelector(selector); + // Cannot nicely deserialize Fuzzy region type + if (regionType == null || regionType == RegionSelectorType.FUZZY) { + return null; + } + return new JsonPrimitive(regionType.toString()); + } + +} 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 a00b26702..5a5fa654e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -125,7 +125,9 @@ public class LocalSession implements TextureHolder { private transient int cuiVersion = CUI_VERSION_UNINITIALIZED; // Session related - private transient RegionSelector selector = new CuboidRegionSelector(); + //FAWE start - allow saving to session store + private RegionSelector selector = new CuboidRegionSelector(); + //FAWE end private transient boolean placeAtPos1 = false; //FAWE start private final transient List history = Collections.synchronizedList(new LinkedList<>() { @@ -771,6 +773,7 @@ public class LocalSession implements TextureHolder { checkNotNull(selector); selector.setWorld(world); this.selector = selector; + setDirty(); if (hasWorldOverride() && !world.equals(getWorldOverride())) { setWorldOverride(null); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 64e3c8a81..a643742d2 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 @@ -755,13 +755,7 @@ public class SelectionCommands { } if (setDefaultSelector) { - RegionSelectorType found = null; - for (RegionSelectorType type : RegionSelectorType.values()) { - if (type.getSelectorClass() == newSelector.getClass()) { - found = type; - break; - } - } + RegionSelectorType found = RegionSelectorType.getForSelector(newSelector); if (found != null) { session.setDefaultRegionSelector(found); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java index 61e46aeab..5c8655893 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java @@ -19,8 +19,14 @@ package com.sk89q.worldedit.regions.selector; +import com.fastasyncworldedit.core.regions.selector.FuzzyRegionSelector; +import com.fastasyncworldedit.core.regions.selector.PolyhedralRegionSelector; import com.sk89q.worldedit.regions.RegionSelector; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; + /** * An enum of default region selector types. */ @@ -32,7 +38,21 @@ public enum RegionSelectorType { SPHERE(SphereRegionSelector.class), ELLIPSOID(EllipsoidRegionSelector.class), POLYGON(Polygonal2DRegionSelector.class), - CONVEX_POLYHEDRON(ConvexPolyhedralRegionSelector.class); + CONVEX_POLYHEDRON(ConvexPolyhedralRegionSelector.class), + //FAWE start + POLYHEDRAL(PolyhedralRegionSelector.class), + FUZZY(FuzzyRegionSelector.class); + //FAWE end + + //FAWE start + private static final Map, RegionSelectorType> VALUE_MAP = new HashMap<>(); + + static { + for (RegionSelectorType type : values()) { + VALUE_MAP.put(type.getSelectorClass(), type); + } + } + //FAWE end private final Class selectorClass; @@ -40,6 +60,19 @@ public enum RegionSelectorType { this.selectorClass = selectorClass; } + //FAWE start + /** + * Get a {@link RegionSelectorType} for the given {@link RegionSelector} + * + * @param selector Region selector to get type enum for + * @since TODO + */ + @Nullable + public static RegionSelectorType getForSelector(RegionSelector selector) { + return VALUE_MAP.get(selector.getClass()); + } + //FAWE end + /** * Get the selector class. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java index d31750e11..e5d05ee6d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java @@ -19,12 +19,14 @@ package com.sk89q.worldedit.util.gson; +import com.fastasyncworldedit.core.util.gson.ItemTypeAdapter; +import com.fastasyncworldedit.core.util.gson.RegionSelectorAdapter; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.world.item.ItemType; -import com.sk89q.worldedit.world.item.ItemTypes; /** * Utility methods for Google's GSON library. @@ -43,7 +45,10 @@ public final class GsonUtil { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter()); gsonBuilder.registerTypeAdapter(BlockVector3.class, new BlockVectorAdapter()); + //FAWE start + gsonBuilder.registerTypeAdapter(RegionSelector.class, new RegionSelectorAdapter()); gsonBuilder.registerTypeAdapter(ItemType.class, new ItemTypeAdapter()); + //FAWE end return gsonBuilder; } From 38242068f043f190b491b84f10b2008cc2fd3a73 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:18:17 +0000 Subject: [PATCH 164/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.1.21 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a6acb6c2e..1b9bef60e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.1.20" +towny = "0.100.1.21" plotsquared = "7.3.6" # Third party From 36da507cf7972a83a45b0fb46de4ceed470e39a3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 19 Mar 2024 19:22:41 +0000 Subject: [PATCH 165/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240319.191757-136 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index f18ef582f..d1250a94f 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240316.193646-135") + the().paperDevBundle("1.20.4-R0.1-20240319.191757-136") compileOnly(libs.paperlib) } From 63d5852b6c73c2851d40a0135bcf897e1c6e999c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Mar 2024 20:46:11 +0000 Subject: [PATCH 166/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240320.194253-137 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index d1250a94f..bc85e188f 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240319.191757-136") + the().paperDevBundle("1.20.4-R0.1-20240320.194253-137") compileOnly(libs.paperlib) } From 68eb24a2f92a084c8a368b8d9bef725248d5f017 Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Wed, 20 Mar 2024 23:39:36 +0100 Subject: [PATCH 167/466] fix: imgur image resolution, image input stream reading (#2637) --- .../core/util/MainUtil.java | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java index cbe9c6897..41c4e5704 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java @@ -40,6 +40,7 @@ import javax.annotation.Nullable; import javax.imageio.ImageIO; import javax.imageio.ImageReadParam; import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; @@ -58,6 +59,9 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; @@ -94,6 +98,10 @@ import static java.lang.System.arraycopy; public class MainUtil { private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static final String CURL_USER_AGENT = "curl/8.1.1"; + private static final HttpClient HTTP_CLIENT = HttpClient.newBuilder() + .followRedirects(HttpClient.Redirect.NORMAL) + .build(); public static List filter(String prefix, List suggestions) { if (prefix.isEmpty()) { @@ -523,25 +531,52 @@ public class MainUtil { } public static BufferedImage readImage(InputStream stream) throws IOException { - Iterator iter = ImageIO.getImageReaders(stream); + final ImageInputStream imageStream = ImageIO.createImageInputStream(stream); + if (imageStream == null) { + throw new IOException("Can't find suitable ImageInputStream"); + } + Iterator iter = ImageIO.getImageReaders(imageStream); if (!iter.hasNext()) { throw new IOException("Could not get image reader from stream."); } ImageReader reader = iter.next(); ImageReadParam param = reader.getDefaultReadParam(); - reader.setInput(stream, true, true); + reader.setInput(imageStream, true, true); BufferedImage bi; try { bi = reader.read(0, param); } finally { reader.dispose(); stream.close(); + imageStream.close(); } return MainUtil.toRGB(bi); } public static BufferedImage readImage(URL url) throws IOException { - return readImage(url.openStream()); + try { + final URI uri = url.toURI(); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).GET(); + + if (uri.getHost().equalsIgnoreCase("i.imgur.com")) { + requestBuilder = requestBuilder.setHeader("User-Agent", CURL_USER_AGENT); + } + + final HttpResponse response = HTTP_CLIENT.send( + requestBuilder.build(), + HttpResponse.BodyHandlers.ofInputStream() + ); + try (final InputStream body = response.body()) { + if (response.statusCode() > 299) { + throw new IOException("Expected 2xx as response code, but received " + response.statusCode()); + } + return readImage(body); + } + } catch (InterruptedException e) { + throw new IOException("request was interrupted", e); + } catch (URISyntaxException e) { + throw new IOException("failed to parse url to uri reference", e); + } } public static BufferedImage readImage(File file) throws IOException { From 07011e242063317bad97ee197afeee66ef0cb380 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Mar 2024 22:40:52 +0000 Subject: [PATCH 168/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240320.215354-140 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index bc85e188f..b225a6875 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240320.194253-137") + the().paperDevBundle("1.20.4-R0.1-20240320.215354-140") compileOnly(libs.paperlib) } From a957af38c09fb8756202bf8bf978bd66f8d71b7f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Mar 2024 22:40:43 +0000 Subject: [PATCH 169/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.1.22 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1b9bef60e..dd3e3d38e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.1.21" +towny = "0.100.1.22" plotsquared = "7.3.6" # Third party From 4b91f6410f519103dec01b6603404fbd6ffee4f8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 22 Mar 2024 17:29:04 +0000 Subject: [PATCH 170/466] Update dependency gradle to v8.7 --- gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 43453 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd4917707c1f8861d8cb53dd15194d4248596..e6441136f3d4ba8a0da8d277868979cfbc8ad796 100644 GIT binary patch delta 34118 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 delta 34176 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 SGW6ptSs!X7{rG*o_g?|vpSEZK diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a80b22ce5..b82aa23a4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 0182d52c02884284068fec30dadad75dc6e2fc7b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 22 Mar 2024 21:14:32 +0000 Subject: [PATCH 171/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.1.23 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index dd3e3d38e..85d7a18c8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.1.22" +towny = "0.100.1.23" plotsquared = "7.3.6" # Third party From 9d20df9e6b81896b3244115515df3a0f896f6658 Mon Sep 17 00:00:00 2001 From: Zeranny Date: Sat, 23 Mar 2024 19:26:13 +0000 Subject: [PATCH 172/466] Fix queryRel returning data value for block at absolute coordinates (#2645) * Replace toWorld with toWorldRel for relative data * re-add accidentally deleted annotation --- .../worldedit/regions/shape/WorldEditExpressionEnvironment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4b87ebcc6..2284b9733 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 @@ -85,7 +85,7 @@ public class WorldEditExpressionEnvironment implements ExpressionEnvironment { @SuppressWarnings("deprecation") @Override public int getBlockDataRel(double x, double y, double z) { - return extent.getBlock(toWorld(x, y, z)).getBlockType().getLegacyCombinedId() & 0xF; + return extent.getBlock(toWorldRel(x, y, z).toBlockPoint()).getBlockType().getLegacyCombinedId() & 0xF; } //FAWE start From 4c98ac2bd877062572507886d5fea0fe8447c4db Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 23 Mar 2024 19:27:44 +0000 Subject: [PATCH 173/466] Update eps1lon/actions-label-merge-conflict action to v3 --- .github/workflows/label-merge-conflicts.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-merge-conflicts.yaml b/.github/workflows/label-merge-conflicts.yaml index d189f5520..fa6f3d72d 100644 --- a/.github/workflows/label-merge-conflicts.yaml +++ b/.github/workflows/label-merge-conflicts.yaml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Label conflicting PRs - uses: eps1lon/actions-label-merge-conflict@v2.1.0 + uses: eps1lon/actions-label-merge-conflict@v3.0.0 with: dirtyLabel: "unresolved-merge-conflict" repoToken: "${{ secrets.GITHUB_TOKEN }}" From 5e234a7003e00674460eed65140f1a619a128d27 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 23 Mar 2024 21:56:42 +0000 Subject: [PATCH 174/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240323.213332-142 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index b225a6875..088dd6f41 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240320.215354-140") + the().paperDevBundle("1.20.4-R0.1-20240323.213332-142") compileOnly(libs.paperlib) } From c10f58ac950ef1a5ac343e4bcdecd7ede067dcaf Mon Sep 17 00:00:00 2001 From: Zeranny Date: Sun, 24 Mar 2024 14:49:58 +0000 Subject: [PATCH 175/466] Fix Linear pattern index incrementing above array length (#2626) * Fix index incrementing above array length in async * Add fork method --- .../function/pattern/LinearBlockPattern.java | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java index 086cf3a31..0b6ef1be9 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java @@ -1,5 +1,6 @@ package com.fastasyncworldedit.core.function.pattern; +import com.fastasyncworldedit.core.queue.Filter; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; @@ -7,6 +8,8 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; +import java.util.Arrays; + public class LinearBlockPattern extends AbstractPattern implements ResettablePattern { private final Pattern[] patternsArray; @@ -15,7 +18,7 @@ public class LinearBlockPattern extends AbstractPattern implements ResettablePat /** * Create a new {@link Pattern} instance * - * @param patterns array of patterns to linearly choose from based on x/z coordinates + * @param patterns array of patterns to linearly choose from */ public LinearBlockPattern(Pattern[] patterns) { this.patternsArray = patterns; @@ -23,18 +26,20 @@ public class LinearBlockPattern extends AbstractPattern implements ResettablePat @Override public BaseBlock applyBlock(BlockVector3 position) { - if (index == patternsArray.length) { - index = 0; - } - return patternsArray[index++].applyBlock(position); + index = (index + 1) % patternsArray.length; + return patternsArray[index].applyBlock(position); } @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - if (index == patternsArray.length) { - index = 0; - } - return patternsArray[index++].apply(extent, get, set); + index = (index + 1) % patternsArray.length; + return patternsArray[index].apply(extent, get, set); + } + + @Override + public Filter fork() { + final Pattern[] forked = Arrays.stream(this.patternsArray).map(Pattern::fork).toArray(Pattern[]::new); + return new LinearBlockPattern(forked); } @Override From 2dee197f2b1fad53827a2a2dcb2f02d84fb2e7a4 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sun, 24 Mar 2024 18:02:16 +0100 Subject: [PATCH 176/466] Use correct find class in ExtentTraverser (#2649) use correct find class in ExtentTraverser --- .../com/fastasyncworldedit/core/util/ExtentTraverser.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ExtentTraverser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ExtentTraverser.java index e7038deaa..6ae147765 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ExtentTraverser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ExtentTraverser.java @@ -51,11 +51,10 @@ public class ExtentTraverser { return last; } - @SuppressWarnings("unchecked") @Nullable - public U findAndGet(Class clazz) { - ExtentTraverser traverser = find(clazz); - return (traverser != null) ? (U) traverser.get() : null; + public U findAndGet(Class clazz) { + ExtentTraverser traverser = find(clazz); + return (traverser != null) ? traverser.get() : null; } @SuppressWarnings("unchecked") From c68544d66d095102511f971bd70ab2533eb9e343 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 12:51:53 +0000 Subject: [PATCH 177/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240325.123556-143 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 088dd6f41..d55d44a76 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240323.213332-142") + the().paperDevBundle("1.20.4-R0.1-20240325.123556-143") compileOnly(libs.paperlib) } From 8095111effa158f1d0e7991768e2ea1317321f6c Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Wed, 27 Mar 2024 15:15:42 +0100 Subject: [PATCH 178/466] Simplify processor ordering (#2651) --- .../extent/processor/MultiBatchProcessor.java | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/MultiBatchProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/MultiBatchProcessor.java index e57ccb490..c266fd544 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/MultiBatchProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/MultiBatchProcessor.java @@ -19,12 +19,9 @@ import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.function.Supplier; @@ -80,28 +77,18 @@ public class MultiBatchProcessor implements IBatchProcessor { @Override public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { - Map> ordered = new HashMap<>(); + Map> ordered = new HashMap<>(); IChunkSet chunkSet = set; for (IBatchProcessor processor : processors) { if (processor.getScope() != ProcessorScope.ADDING_BLOCKS) { - ordered.merge( - processor.getScope().intValue(), - new HashSet<>(Collections.singleton(processor)), - (existing, theNew) -> { - existing.add(processor); - return existing; - } - ); + ordered.computeIfAbsent(processor.getScope().intValue(), k -> new ArrayList<>()) + .add(processor); continue; } chunkSet = processSet(processor, chunk, get, chunkSet); } - if (ordered.size() > 0) { - for (int i = 1; i <= 4; i++) { - Set processors = ordered.get(i); - if (processors == null) { - continue; - } + if (!ordered.isEmpty()) { + for (List processors : ordered.values()) { for (IBatchProcessor processor : processors) { chunkSet = processSet(processor, chunk, get, chunkSet); if (chunkSet == null) { From 7b8c7894bae20f30acb1504028d591e205a025b7 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Wed, 27 Mar 2024 15:16:06 +0100 Subject: [PATCH 179/466] Make usage of stateful patterns thread-safe (#2633) * Make usage of No(Axis)Patterns thread-safe * make more pattern usage thread-safe * make more WE patterns thread safe * remove StatefulPattern --- .../core/function/pattern/ExpressionPattern.java | 6 ++++++ .../function/pattern/Linear2DBlockPattern.java | 8 ++++++++ .../function/pattern/Linear3DBlockPattern.java | 8 ++++++++ .../core/function/pattern/LinearBlockPattern.java | 6 ++++++ .../core/function/pattern/MaskedPattern.java | 5 +++++ .../core/function/pattern/NoXPattern.java | 5 +++++ .../core/function/pattern/NoYPattern.java | 5 +++++ .../core/function/pattern/NoZPattern.java | 6 ++++++ .../core/function/pattern/OffsetPattern.java | 5 +++++ .../function/pattern/RandomOffsetPattern.java | 5 +++++ .../core/function/pattern/RelativePattern.java | 7 +++++++ .../pattern/SolidRandomOffsetPattern.java | 5 +++++ .../pattern/SurfaceRandomOffsetPattern.java | 5 +++++ .../extent/buffer/ForgetfulExtentBuffer.java | 7 +++++++ .../pattern/ExtentBufferedCompositePattern.java | 10 ++++++++++ .../sk89q/worldedit/function/pattern/Pattern.java | 5 +++++ .../worldedit/function/pattern/RandomPattern.java | 15 +++++++++++++++ .../function/pattern/StateApplyingPattern.java | 5 ++++- 18 files changed, 117 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExpressionPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExpressionPattern.java index a9c1ec962..638872ea8 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExpressionPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExpressionPattern.java @@ -1,6 +1,7 @@ package com.fastasyncworldedit.core.function.pattern; import com.sk89q.worldedit.function.pattern.AbstractPattern; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.expression.EvaluationException; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; @@ -57,4 +58,9 @@ public class ExpressionPattern extends AbstractPattern { } } + @Override + public Pattern fork() { + return new ExpressionPattern(this.expression.clone()); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java index 523f22541..e99383d06 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java @@ -7,6 +7,8 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; +import java.util.Arrays; + import static java.lang.Math.floorDiv; /** @@ -52,4 +54,10 @@ public class Linear2DBlockPattern extends AbstractPattern { return patternsArray[index].apply(extent, get, set); } + @Override + public Pattern fork() { + final Pattern[] forked = Arrays.stream(this.patternsArray).map(Pattern::fork).toArray(Pattern[]::new); + return new Linear2DBlockPattern(forked, this.xScale, this.zScale); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java index ea2e37588..e4d3822cc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java @@ -7,6 +7,8 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; +import java.util.Arrays; + import static java.lang.Math.floorDiv; /** @@ -56,4 +58,10 @@ public class Linear3DBlockPattern extends AbstractPattern { return patternsArray[index].apply(extent, get, set); } + @Override + public Pattern fork() { + final Pattern[] forked = Arrays.stream(this.patternsArray).map(Pattern::fork).toArray(Pattern[]::new); + return new Linear3DBlockPattern(forked, this.xScale, this.yScale, this.zScale); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java index 0b6ef1be9..c65918e89 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java @@ -47,4 +47,10 @@ public class LinearBlockPattern extends AbstractPattern implements ResettablePat index = 0; } + @Override + public Pattern fork() { + final Pattern[] forked = Arrays.stream(this.patternsArray).map(Pattern::fork).toArray(Pattern[]::new); + return new LinearBlockPattern(forked); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/MaskedPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/MaskedPattern.java index 5d840d771..a5210feba 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/MaskedPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/MaskedPattern.java @@ -43,4 +43,9 @@ public class MaskedPattern extends AbstractPattern { return secondary.apply(extent, get, set); } + @Override + public Pattern fork() { + return new MaskedPattern(this.mask.copy(), this.primary.fork(), this.secondary.fork()); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoXPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoXPattern.java index d9fefb1bc..b4e9aac37 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoXPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoXPattern.java @@ -36,4 +36,9 @@ public class NoXPattern extends AbstractPattern { return pattern.apply(extent, mutable, set); } + @Override + public Pattern fork() { + return new NoXPattern(this.pattern.fork()); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoYPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoYPattern.java index 05d26f496..2fefaedfc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoYPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoYPattern.java @@ -36,4 +36,9 @@ public class NoYPattern extends AbstractPattern { return pattern.apply(extent, mutable, set); } + @Override + public Pattern fork() { + return new NoYPattern(this.pattern.fork()); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoZPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoZPattern.java index faebb59aa..8c100c5e3 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoZPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoZPattern.java @@ -1,6 +1,7 @@ package com.fastasyncworldedit.core.function.pattern; import com.fastasyncworldedit.core.math.MutableBlockVector3; +import com.fastasyncworldedit.core.queue.Filter; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; @@ -36,4 +37,9 @@ public class NoZPattern extends AbstractPattern { return pattern.apply(extent, mutable, set); } + @Override + public Pattern fork() { + return new NoZPattern(this.pattern.fork()); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java index 894f9d06a..628b848e8 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java @@ -60,4 +60,9 @@ public class OffsetPattern extends AbstractPattern { return pattern.apply(extent, get, mutable); } + @Override + public Pattern fork() { + return new OffsetPattern(this.pattern.fork(), this.dx, this.dy, this.dz, this.minY, this.maxY); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java index 3eb5c3b77..c0afd02e3 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java @@ -72,4 +72,9 @@ public class RandomOffsetPattern extends AbstractPattern { return pattern.apply(extent, get, mutable); } + @Override + public Pattern fork() { + return new RandomOffsetPattern(this.pattern.fork(), this.dx, this.dy, this.dz, this.minY, this.maxY); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RelativePattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RelativePattern.java index cda875f04..541aaa494 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RelativePattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RelativePattern.java @@ -63,4 +63,11 @@ public class RelativePattern extends AbstractPattern implements ResettablePatter origin = null; } + @Override + public Pattern fork() { + RelativePattern forked = new RelativePattern(this.pattern.fork(), this.minY, this.maxY); + forked.origin = this.origin; // maintain origin for forks + return forked; + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SolidRandomOffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SolidRandomOffsetPattern.java index 12b64a497..54ecf6676 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SolidRandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SolidRandomOffsetPattern.java @@ -94,4 +94,9 @@ public class SolidRandomOffsetPattern extends AbstractPattern { return pattern.apply(extent, get, set); } + @Override + public Pattern fork() { + return new SolidRandomOffsetPattern(this.pattern.fork(), this.dx, this.dy, this.dz, this.minY, this.maxY); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java index 73327f94a..34866fc54 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java @@ -129,4 +129,9 @@ public class SurfaceRandomOffsetPattern extends AbstractPattern { return !block.getBlockType().getMaterial().isMovementBlocker(); } + @Override + public Pattern fork() { + return new SurfaceRandomOffsetPattern(this.pattern.fork(), this.moves, this.minY, this.maxY); + } + } 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 f569acd00..ca2bfd965 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 @@ -235,4 +235,11 @@ public class ForgetfulExtentBuffer extends AbstractDelegateExtent implements Pat }; } + //FAWE - stateful pattern + @Override + public Pattern fork() { + return new ForgetfulExtentBuffer(extent, mask.copy()); + } + //FAWE end + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/ExtentBufferedCompositePattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/ExtentBufferedCompositePattern.java index 49e7f5472..863cf1e25 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/ExtentBufferedCompositePattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/ExtentBufferedCompositePattern.java @@ -25,6 +25,8 @@ import com.sk89q.worldedit.extent.buffer.ExtentBuffer; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; +import java.util.Arrays; + import static com.google.common.base.Preconditions.checkArgument; /** @@ -64,4 +66,12 @@ public class ExtentBufferedCompositePattern extends AbstractExtentPattern { return lastBlock; } + //FAWE - stateful pattern + @Override + public Pattern fork() { + final Pattern[] forkedPatterns = Arrays.stream(patterns).map(Pattern::fork).toArray(Pattern[]::new); + return new ExtentBufferedCompositePattern(getExtent(), forkedPatterns); + } + //FAWE end + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java index 801b07a65..ab284c0cf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java @@ -59,6 +59,11 @@ public interface Pattern extends Filter { apply(block, block, block); } + @Override + default Pattern fork() { // covariant return type + return this; + } + //FAWE end /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java index 1d2df7223..c45629e5f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java @@ -67,6 +67,13 @@ public class RandomPattern extends AbstractPattern { this.collection = RandomCollection.of(weights, random); this.patterns = parent.patterns; } + + private RandomPattern(SimpleRandom random, Map weights) { + this.random = random; + this.weights = weights; + this.collection = RandomCollection.of(weights, random); + this.patterns = new LinkedHashSet<>(weights.keySet()); + } //FAWE end /** @@ -107,6 +114,14 @@ public class RandomPattern extends AbstractPattern { public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { return collection.next(get.getBlockX(), get.getBlockY(), get.getBlockZ()).apply(extent, get, set); } + + @Override + public Pattern fork() { + final LinkedHashMap newWeights = new LinkedHashMap<>(); + this.weights.forEach((p, w) -> newWeights.put(p.fork(), w)); + return new RandomPattern(this.random, newWeights); + } + //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/StateApplyingPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/StateApplyingPattern.java index 3d834f76b..b328e78ea 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/StateApplyingPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/StateApplyingPattern.java @@ -29,13 +29,16 @@ import com.sk89q.worldedit.world.block.BlockType; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; import static com.sk89q.worldedit.blocks.Blocks.resolveProperties; public class StateApplyingPattern extends AbstractExtentPattern { private final Map states; - private final Map, Object>> cache = Maps.newHashMap(); + //FAWE - avoid race conditions + private final Map, Object>> cache = new ConcurrentHashMap<>(); + //FAWE end public StateApplyingPattern(Extent extent, Map statesToSet) { super(extent); From c1c3a5f7ed4d7223150e9fe23173ce8d75101796 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Wed, 27 Mar 2024 16:32:11 +0000 Subject: [PATCH 180/466] fix: git did not find conflict here, remove duplicate fork method --- .../core/function/pattern/LinearBlockPattern.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java index c65918e89..1490bf37d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java @@ -36,12 +36,6 @@ public class LinearBlockPattern extends AbstractPattern implements ResettablePat return patternsArray[index].apply(extent, get, set); } - @Override - public Filter fork() { - final Pattern[] forked = Arrays.stream(this.patternsArray).map(Pattern::fork).toArray(Pattern[]::new); - return new LinearBlockPattern(forked); - } - @Override public void reset() { index = 0; From 4a767926c1ddaed7c9dc48f3024820790f1c2a9c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 27 Mar 2024 21:58:06 +0000 Subject: [PATCH 181/466] Update dependency io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin to v1.5.12 --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index e4227d576..878f1b845 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -24,7 +24,7 @@ dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2") implementation("com.github.johnrengelman:shadow:8.1.1") - implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.11") + implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.12") } kotlin { From b60a0c532c6b76d9b943a5f19a9cfca211242845 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Mar 2024 19:56:45 +0000 Subject: [PATCH 182/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240329.175742-144 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index d55d44a76..3e2bbe382 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240325.123556-143") + the().paperDevBundle("1.20.4-R0.1-20240329.175742-144") compileOnly(libs.paperlib) } From 23bcdb0409e46f59776526946e7121f4e37c10bf Mon Sep 17 00:00:00 2001 From: Jordan Date: Sat, 30 Mar 2024 10:31:52 +0100 Subject: [PATCH 183/466] fix: introduce approx size to patterns and use in ScatterBrush (#2631) * fix: introduce approx size to patterns and use in ScatterBrush - fixes #2610 * Do not use patternsize in blockvectorset offset --- .../core/command/tool/brush/ScatterBrush.java | 34 +++++++- .../core/command/tool/brush/ShatterBrush.java | 5 +- .../core/function/pattern/OffsetPattern.java | 7 ++ .../pattern/RandomFullClipboardPattern.java | 16 ++++ .../function/pattern/RandomOffsetPattern.java | 5 ++ .../pattern/SurfaceRandomOffsetPattern.java | 5 ++ .../core/math/BlockVectorSet.java | 43 +++++++++++ .../core/math/LocalBlockVectorSet.java | 31 ++------ .../core/math/MutableBlockVector3.java | 16 ++++ .../core/util/collection/BlockVector3Set.java | 77 +++++++++++++++---- .../worldedit/function/pattern/Pattern.java | 11 +++ 11 files changed, 208 insertions(+), 42 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterBrush.java index 7ea15e421..5e6c9ac52 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterBrush.java @@ -5,6 +5,7 @@ import com.fastasyncworldedit.core.function.mask.RadiusMask; import com.fastasyncworldedit.core.function.mask.SurfaceMask; import com.fastasyncworldedit.core.math.BlockVectorSet; import com.fastasyncworldedit.core.math.LocalBlockVectorSet; +import com.fastasyncworldedit.core.util.collection.BlockVector3Set; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.command.tool.brush.Brush; @@ -64,8 +65,9 @@ public class ScatterBrush implements Brush { length = 1; visited.add(position); } - LocalBlockVectorSet placed = new LocalBlockVectorSet(); - placed.setOffset(position.getX(), position.getZ()); + BlockVector3 patternSize = pattern.size(); + BlockVector3Set placed = BlockVector3Set.getAppropriateVectorSet(patternSize.add(distance, distance, distance)); + placed.setOffset(position.getX(), position.getY(), position.getZ()); int maxFails = 1000; for (int i = 0; i < count; i++) { int index = ThreadLocalRandom.current().nextInt(length); @@ -88,7 +90,20 @@ public class ScatterBrush implements Brush { finish(editSession, placed, position, pattern, size); } + /** + * @deprecated Use {@link ScatterBrush#finish(EditSession, BlockVector3Set, BlockVector3, Pattern, double)} + */ + @Deprecated(forRemoval = true, since = "TODO") public void finish(EditSession editSession, LocalBlockVectorSet placed, BlockVector3 pos, Pattern pattern, double size) { + finish(editSession, (BlockVector3Set) placed, pos, pattern, size); + } + + /** + * Complete the scatter brush process. + * + * @since TODO + */ + public void finish(EditSession editSession, BlockVector3Set placed, BlockVector3 pos, Pattern pattern, double size) { } public boolean canApply(BlockVector3 pos) { @@ -99,8 +114,23 @@ public class ScatterBrush implements Brush { return surface.direction(pt); } + + /** + * @deprecated Use {@link ScatterBrush#apply(EditSession, BlockVector3Set, BlockVector3, Pattern, double)} + */ + @Deprecated(forRemoval = true, since = "TODO") public void apply(EditSession editSession, LocalBlockVectorSet placed, BlockVector3 pt, Pattern p, double size) throws MaxChangedBlocksException { + apply(editSession, (BlockVector3Set) placed, pt, p, size); + } + + /** + * Apply the scatter brush to a given position + * + * @since TODO + */ + public void apply(EditSession editSession, BlockVector3Set placed, BlockVector3 pt, Pattern p, double size) throws + MaxChangedBlocksException { editSession.setBlock(pt, p); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ShatterBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ShatterBrush.java index 58fdb4997..41b36e12c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ShatterBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ShatterBrush.java @@ -3,6 +3,7 @@ package com.fastasyncworldedit.core.command.tool.brush; import com.fastasyncworldedit.core.function.mask.SurfaceMask; import com.fastasyncworldedit.core.math.LocalBlockVectorSet; import com.fastasyncworldedit.core.math.MutableBlockVector3; +import com.fastasyncworldedit.core.util.collection.BlockVector3Set; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.function.mask.Mask; @@ -24,7 +25,7 @@ public class ShatterBrush extends ScatterBrush { @Override public void apply( final EditSession editSession, - final LocalBlockVectorSet placed, + final BlockVector3Set placed, final BlockVector3 position, Pattern p, double size @@ -34,7 +35,7 @@ public class ShatterBrush extends ScatterBrush { @Override public void finish( EditSession editSession, - LocalBlockVectorSet placed, + BlockVector3Set placed, final BlockVector3 position, Pattern pattern, double size diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java index 628b848e8..9a5ca2ceb 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java @@ -60,6 +60,13 @@ public class OffsetPattern extends AbstractPattern { return pattern.apply(extent, get, mutable); } + @Override + public BlockVector3 size() { + // Not exactly the "size" but offset should be taken into consideration in most + // places where the "size" matters + return BlockVector3.at(dx, dy, dz); + } + @Override public Pattern fork() { return new OffsetPattern(this.pattern.fork(), this.dx, this.dy, this.dz, this.minY, this.maxY); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomFullClipboardPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomFullClipboardPattern.java index 52348780b..957cf2617 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomFullClipboardPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomFullClipboardPattern.java @@ -1,7 +1,9 @@ package com.fastasyncworldedit.core.function.pattern; +import com.fastasyncworldedit.core.math.MutableBlockVector3; import com.sk89q.worldedit.WorldEditException; 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.pattern.AbstractPattern; import com.sk89q.worldedit.function.pattern.Pattern; @@ -9,6 +11,8 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.world.block.BaseBlock; @@ -23,6 +27,7 @@ public class RandomFullClipboardPattern extends AbstractPattern { private final boolean randomRotate; private final boolean randomFlip; private final Vector3 flipVector = Vector3.at(1, 0, 0).multiply(-2).add(1, 1, 1); + private final BlockVector3 size; /** * Create a new {@link Pattern} instance @@ -34,6 +39,12 @@ public class RandomFullClipboardPattern extends AbstractPattern { public RandomFullClipboardPattern(List clipboards, boolean randomRotate, boolean randomFlip) { checkNotNull(clipboards); this.clipboards = clipboards; + MutableBlockVector3 mut = new MutableBlockVector3(); + clipboards.stream().flatMap(c -> c.getClipboards().stream()).map(c -> { + Region region = c.getRegion(); + return region.getMaximumPoint().subtract(c.getOrigin().getMinimum(region.getMinimumPoint())); + }).forEach(mut::getMaximum); + this.size = mut.toImmutable(); this.randomRotate = randomRotate; this.randomFlip = randomFlip; } @@ -66,4 +77,9 @@ public class RandomFullClipboardPattern extends AbstractPattern { throw new IllegalStateException("Incorrect use. This pattern can only be applied to an extent!"); } + @Override + public BlockVector3 size() { + return size; + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java index c0afd02e3..c68bb24b1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java @@ -72,6 +72,11 @@ public class RandomOffsetPattern extends AbstractPattern { return pattern.apply(extent, get, mutable); } + @Override + public BlockVector3 size() { + return BlockVector3.at(dx2, dy2, dz2); + } + @Override public Pattern fork() { return new RandomOffsetPattern(this.pattern.fork(), this.dx, this.dy, this.dz, this.minY, this.maxY); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java index 34866fc54..03e3126be 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java @@ -129,6 +129,11 @@ public class SurfaceRandomOffsetPattern extends AbstractPattern { return !block.getBlockType().getMaterial().isMovementBlocker(); } + @Override + public BlockVector3 size() { + return BlockVector3.at(moves, moves, moves); + } + @Override public Pattern fork() { return new SurfaceRandomOffsetPattern(this.pattern.fork(), this.moves, this.minY, this.maxY); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java index e904244de..67aeadec8 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java @@ -78,6 +78,49 @@ public class BlockVectorSet extends AbstractCollection implements return localMap != null && localMap.contains(x & 2047, ((y + 128) & 511) - 128, z & 2047); } + @Override + public void setOffset(final int x, final int z) { + // Do nothing + } + + @Override + public void setOffset(final int x, final int y, final int z) { + // Do nothing + } + + @Override + public boolean containsRadius(final int x, final int y, final int z, final int radius) { + if (radius <= 0) { + return contains(x, y, z); + } + // Quick corners check + if (!contains(x - radius, y, z - radius)) { + return false; + } + if (!contains(x + radius, y, z + radius)) { + return false; + } + if (!contains(x - radius, y, z + radius)) { + return false; + } + if (!contains(x + radius, y, z - radius)) { + return false; + } + // Slow but if someone wants to think of an elegant way then feel free to add it + for (int xx = -radius; xx <= radius; xx++) { + int rx = x + xx; + for (int yy = -radius; yy <= radius; yy++) { + int ry = y + yy; + for (int zz = -radius; zz <= radius; zz++) { + if (contains(rx, ry, z + zz)) { + return true; + } + } + } + } + return false; + } + @Override public boolean contains(Object o) { if (o instanceof BlockVector3 v) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/LocalBlockVectorSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/LocalBlockVectorSet.java index 8e6cdabe8..2ed3a2f63 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/LocalBlockVectorSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/LocalBlockVectorSet.java @@ -100,14 +100,7 @@ public class LocalBlockVectorSet implements BlockVector3Set { return new LocalBlockVectorSet(offsetX, offsetY, offsetZ, set.clone()); } - /** - * If a radius is contained by the set - * - * @param x x radius center - * @param y y radius center - * @param z z radius center - * @return if radius is contained by the set - */ + @Override public boolean containsRadius(int x, int y, int z, int radius) { if (radius <= 0) { return contains(x, y, z); @@ -130,9 +123,11 @@ public class LocalBlockVectorSet implements BlockVector3Set { return false; } for (int xx = -radius; xx <= radius; xx++) { + int rx = x + xx; for (int yy = -radius; yy <= radius; yy++) { + int ry = y + yy; for (int zz = -radius; zz <= radius; zz++) { - if (contains(x + xx, y + yy, z + zz)) { + if (contains(rx, ry, z + zz)) { return true; } } @@ -141,27 +136,13 @@ public class LocalBlockVectorSet implements BlockVector3Set { return false; } - /** - * Set the offset applied to values when storing and reading to keep the values within -1024 to 1023. Uses default y offset - * of 128 to allow -64 -> 320 world height use. - * - * @param x x offset - * @param z z offset - */ + @Override public void setOffset(int x, int z) { this.offsetX = x; this.offsetZ = z; } - /** - * Set the offset applied to values when storing and reading to keep the x and z values within -1024 to 1023. Y values - * require keeping withing -256 and 255. - * - * @param x x offset - * @param y y offset - * @param z z offset - * @since 2.2.0 - */ + @Override public void setOffset(int x, int y, int z) { this.offsetX = x; this.offsetY = y; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableBlockVector3.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableBlockVector3.java index baa20163f..6ebabae1d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableBlockVector3.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableBlockVector3.java @@ -61,6 +61,22 @@ public class MutableBlockVector3 extends BlockVector3 { return z; } + @Override + public BlockVector3 getMinimum(BlockVector3 v2) { + this.x = Math.min(v2.getX(), x); + this.y = Math.min(v2.getY(), y); + this.z = Math.min(v2.getZ(), z); + return this; + } + + @Override + public BlockVector3 getMaximum(BlockVector3 v2) { + this.x = Math.max(v2.getX(), x); + this.y = Math.max(v2.getY(), y); + this.z = Math.max(v2.getZ(), z); + return this; + } + @Override public MutableBlockVector3 mutX(double x) { this.x = (int) x; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java index 881aaf9f3..83a639ead 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java @@ -9,29 +9,80 @@ import java.util.Set; public interface BlockVector3Set extends Set { + /** + * Get the appropriate {@link BlockVector3Set} implementation for the given region. Either {@link LocalBlockVectorSet} or + * {@link BlockVectorSet}. Sets the offset if using {@link LocalBlockVectorSet}. + * + * @param region Region to get for + * @return Appropriate {@link BlockVector3Set} implementation + */ static BlockVector3Set getAppropriateVectorSet(Region region) { BlockVector3 max = region.getMaximumPoint(); BlockVector3 min = region.getMinimumPoint(); - BlockVector3 size = region.getDimensions(); + BlockVector3Set set = getAppropriateVectorSet(region.getDimensions()); + // Set default offset as many operations utilising a region are likely to start in a corner, this initialising the + // LocalBlockVectorSet poorly + // This needs to be ceiling as LocalBlockVector extends 1 block further "negative" + int offsetX = (int) Math.ceil((min.getX() + max.getX()) / 2d); + int offsetZ = (int) Math.ceil((min.getZ() + max.getZ()) / 2d); + int offsetY; + if (region.getMinimumY() < -128 || region.getMaximumY() > 320) { + offsetY = (min.getY() + max.getY()) / 2; + } else { + offsetY = 128; + } + set.setOffset(offsetX, offsetY, offsetZ); + return set; + } + + /** + * Get the appropriate {@link BlockVector3Set} implementation for the given dimensions. Either {@link LocalBlockVectorSet} or + * {@link BlockVectorSet}. The offset should be manually set. + * + * @param size Dimensions to get for + * @return Appropriate {@link BlockVector3Set} implementation + */ + static BlockVector3Set getAppropriateVectorSet(BlockVector3 size) { if (size.getBlockX() > 2048 || size.getBlockZ() > 2048 || size.getBlockY() > 512) { return new BlockVectorSet(); } else { - // Set default offset as many operations utilising a region are likely to start in a corner, this initialising the - // LocalBlockVectorSet poorly - // This needs to be ceiling as LocalBlockVector extends 1 block further "negative" - int offsetX = (int) Math.ceil((min.getX() + max.getX()) / 2d); - int offsetZ = (int) Math.ceil((min.getZ() + max.getZ()) / 2d); - int offsetY; - if (region.getMinimumY() < -128 || region.getMaximumY() > 320) { - offsetY = (min.getY() + max.getY()) / 2; - } else { - offsetY = 128; - } - return new LocalBlockVectorSet(offsetX, offsetY, offsetZ); + return new LocalBlockVectorSet(); } } boolean add(int x, int y, int z); boolean contains(int x, int y, int z); + /** + * Set the offset applied to values when storing and reading to keep the values within -1024 to 1023. Uses default y offset + * of 128 to allow -64 -> 320 world height use. + * + * @param x x offset + * @param z z offset + * @since TODO + */ + void setOffset(int x, int z); + + /** + * Set the offset applied to values when storing and reading to keep the x and z values within -1024 to 1023. Y values + * require keeping withing -256 and 255. + * + * @param x x offset + * @param y y offset + * @param z z offset + * @since TODO + */ + void setOffset(int x, int y, int z); + + /** + * If a radius is contained by the set + * + * @param x x radius center + * @param y y radius center + * @param z z radius center + * @return if radius is contained by the set + * @since TODO + */ + boolean containsRadius(int x, int y, int z, int radius); + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java index ab284c0cf..e44a1c19d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java @@ -25,6 +25,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.block.BaseBlock; /** @@ -74,4 +75,14 @@ public interface Pattern extends Filter { */ BaseBlock applyBlock(BlockVector3 position); + /** + * Get the likely maximum size of the volume this pattern will affect + * + * @return Pattern size + * @since TODO + */ + default BlockVector3 size() { + return BlockVector3.ONE; + } + } From 673233c777f5637cfad37412b62563bf6fa347ca Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 30 Mar 2024 09:33:30 +0000 Subject: [PATCH 184/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.1.24 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 85d7a18c8..8862924f5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.1.23" +towny = "0.100.1.24" plotsquared = "7.3.6" # Third party From 628d894244282ffa4e6a9d2600bd2c8050f6bf22 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 31 Mar 2024 04:21:01 +0000 Subject: [PATCH 185/466] Update piston to v0.5.9 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8862924f5..5d66014f2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -43,7 +43,7 @@ serverlib = "2.3.4" ## Internal text-adapter = "3.0.6" text = "3.0.4" -piston = "0.5.8" +piston = "0.5.9" # Tests mockito = "5.11.0" From 91b4393190d6ec51f08dc871ad5b505e5020e374 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 31 Mar 2024 19:27:29 +0000 Subject: [PATCH 186/466] Update piston to v0.5.10 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5d66014f2..f6d16d21d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -43,7 +43,7 @@ serverlib = "2.3.4" ## Internal text-adapter = "3.0.6" text = "3.0.4" -piston = "0.5.9" +piston = "0.5.10" # Tests mockito = "5.11.0" From af547e072c0d8bc78fbcd667d5bc411ebfaf24b7 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Mon, 1 Apr 2024 12:34:19 +0200 Subject: [PATCH 187/466] List FAWE class additions in Javadocs (#2659) * List FAWE class additions in Javadocs Signed-off-by: Alexander Brandes * Update worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/package-info.java --------- Signed-off-by: Alexander Brandes --- .../com/sk89q/worldedit/cli/package-info.java | 2 +- .../command/argument/package-info.java | 4 ++-- .../sk89q/worldedit/command/package-info.java | 2 +- .../command/util/annotation/package-info.java | 18 +++++++++--------- .../function/operation/package-info.java | 2 +- .../worldedit/world/block/package-info.java | 2 +- .../worldedit/world/chunk/package-info.java | 4 ++-- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/package-info.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/package-info.java index 11ccf05d1..60e756259 100644 --- a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/package-info.java +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/package-info.java @@ -1,6 +1,6 @@ /** * The following classes are FAWE additions: * - * @see com.sk89q.worldedit.cli.AccessPoint + * {@link com.sk89q.worldedit.cli.AccessPoint} */ package com.sk89q.worldedit.cli; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/package-info.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/package-info.java index 270468aa1..d1bd7bbd3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/package-info.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/package-info.java @@ -20,8 +20,8 @@ /** * The following classes are FAWE additions: * - * @see com.sk89q.worldedit.command.argument.ExpressionConverter - * @see com.sk89q.worldedit.command.argument.LocationConverter + * {@link com.sk89q.worldedit.command.argument.ExpressionConverter}, + * {@link com.sk89q.worldedit.command.argument.LocationConverter} */ @org.enginehub.piston.util.NonnullByDefault package com.sk89q.worldedit.command.argument; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/package-info.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/package-info.java index 61d4ea41d..4ffda131d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/package-info.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/package-info.java @@ -1,6 +1,6 @@ /** * The following classes are FAWE additions: * - * @see com.sk89q.worldedit.command.HistorySubCommands + * {@link com.sk89q.worldedit.command.HistorySubCommands} */ package com.sk89q.worldedit.command; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/package-info.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/package-info.java index dc15d98d6..006432a73 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/package-info.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/package-info.java @@ -1,14 +1,14 @@ /** * The following classes are FAWE additions: * - * @see com.sk89q.worldedit.command.util.annotation.AllowedRegion - * @see com.sk89q.worldedit.command.util.annotation.Confirm - * @see com.sk89q.worldedit.command.util.annotation.ConfirmHandler - * @see com.sk89q.worldedit.command.util.annotation.Link - * @see com.sk89q.worldedit.command.util.annotation.PatternList - * @see com.sk89q.worldedit.command.util.annotation.Preload - * @see com.sk89q.worldedit.command.util.annotation.PreloadHandler - * @see com.sk89q.worldedit.command.util.annotation.Step - * @see com.sk89q.worldedit.command.util.annotation.Time + * {@link com.sk89q.worldedit.command.util.annotation.AllowedRegion}, + * {@link com.sk89q.worldedit.command.util.annotation.Confirm}, + * {@link com.sk89q.worldedit.command.util.annotation.ConfirmHandler}, + * {@link com.sk89q.worldedit.command.util.annotation.Link}, + * {@link com.sk89q.worldedit.command.util.annotation.PatternList}, + * {@link com.sk89q.worldedit.command.util.annotation.Preload}, + * {@link com.sk89q.worldedit.command.util.annotation.PreloadHandler}, + * {@link com.sk89q.worldedit.command.util.annotation.Step}, + * {@link com.sk89q.worldedit.command.util.annotation.Time} */ package com.sk89q.worldedit.command.util.annotation; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/package-info.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/package-info.java index 5b9eb7485..13a3d4e7c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/package-info.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/package-info.java @@ -1,6 +1,6 @@ /** * The following classes are FAWE additions: * - * @see com.sk89q.worldedit.function.operation.BackwardsExtentBlockCopy + * {@link com.sk89q.worldedit.function.operation.BackwardsExtentBlockCopy} */ package com.sk89q.worldedit.function.operation; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/package-info.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/package-info.java index b8e54bc04..46a6490c9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/package-info.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/package-info.java @@ -1,6 +1,6 @@ /** * The following classes are FAWE additions: * - * @see com.sk89q.worldedit.world.block.BlockTypesCache + * {@link com.sk89q.worldedit.world.block.BlockTypesCache} */ package com.sk89q.worldedit.world.block; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/package-info.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/package-info.java index ecb29c521..5ec273554 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/package-info.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/package-info.java @@ -1,7 +1,7 @@ /** * The following classes are FAWE additions: * - * @see com.sk89q.worldedit.world.chunk.AnvilChunk15 - * @see com.sk89q.worldedit.world.chunk.AnvilChunk17 + * {@link com.sk89q.worldedit.world.chunk.AnvilChunk15}, + * {@link com.sk89q.worldedit.world.chunk.AnvilChunk17} */ package com.sk89q.worldedit.world.chunk; From 4ac3f5ba1a2d4e3bace137913f1640ae1e450c24 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Apr 2024 09:32:10 +0000 Subject: [PATCH 188/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.2.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f6d16d21d..f1c25e764 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.1.24" +towny = "0.100.2.0" plotsquared = "7.3.6" # Third party From 778c212e853b6c08c8ce65b2e1af9fb17c6d9dde Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:08:53 +0000 Subject: [PATCH 189/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240402.103709-145 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 3e2bbe382..e4539cd79 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240329.175742-144") + the().paperDevBundle("1.20.4-R0.1-20240402.103709-145") compileOnly(libs.paperlib) } From 5e10c98915795206be8cacf3dd2a3b46f3412786 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Thu, 4 Apr 2024 21:56:07 +0200 Subject: [PATCH 190/466] Release 2.9.2 Signed-off-by: Alexander Brandes --- build.gradle.kts | 2 +- .../core/command/tool/brush/ScatterBrush.java | 8 ++++---- .../fastasyncworldedit/core/extent/TransformExtent.java | 2 +- .../core/function/pattern/Linear2DBlockPattern.java | 2 +- .../core/function/pattern/Linear3DBlockPattern.java | 2 +- .../core/math/random/Linear2DRandom.java | 2 +- .../core/math/random/Linear3DRandom.java | 2 +- .../core/util/collection/BlockVector3Set.java | 6 +++--- .../com/sk89q/worldedit/function/pattern/Pattern.java | 2 +- .../worldedit/regions/selector/RegionSelectorType.java | 2 +- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 15845439a..8c2685561 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s-%s", rootVersion, buildNumber) +version = String.format("%s", rootVersion) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterBrush.java index 5e6c9ac52..e14d0c599 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterBrush.java @@ -93,7 +93,7 @@ public class ScatterBrush implements Brush { /** * @deprecated Use {@link ScatterBrush#finish(EditSession, BlockVector3Set, BlockVector3, Pattern, double)} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.9.2") public void finish(EditSession editSession, LocalBlockVectorSet placed, BlockVector3 pos, Pattern pattern, double size) { finish(editSession, (BlockVector3Set) placed, pos, pattern, size); } @@ -101,7 +101,7 @@ public class ScatterBrush implements Brush { /** * Complete the scatter brush process. * - * @since TODO + * @since 2.9.2 */ public void finish(EditSession editSession, BlockVector3Set placed, BlockVector3 pos, Pattern pattern, double size) { } @@ -118,7 +118,7 @@ public class ScatterBrush implements Brush { /** * @deprecated Use {@link ScatterBrush#apply(EditSession, BlockVector3Set, BlockVector3, Pattern, double)} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.9.2") public void apply(EditSession editSession, LocalBlockVectorSet placed, BlockVector3 pt, Pattern p, double size) throws MaxChangedBlocksException { apply(editSession, (BlockVector3Set) placed, pt, p, size); @@ -127,7 +127,7 @@ public class ScatterBrush implements Brush { /** * Apply the scatter brush to a given position * - * @since TODO + * @since 2.9.2 */ public void apply(EditSession editSession, BlockVector3Set placed, BlockVector3 pt, Pattern p, double size) throws MaxChangedBlocksException { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java index 64b940d97..250227439 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java @@ -15,7 +15,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; /** * @deprecated Unused internal, will be removed in v3 */ -@Deprecated(forRemoval = true, since = "TODO") +@Deprecated(forRemoval = true, since = "2.9.2") public class TransformExtent extends BlockTransformExtent { private final MutableVector3 mutable1 = new MutableVector3(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java index e99383d06..13df9ca6f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java @@ -15,7 +15,7 @@ import static java.lang.Math.floorDiv; * @deprecated replaced by {@link com.sk89q.worldedit.function.pattern.RandomPattern} * combined with {@link com.fastasyncworldedit.core.math.random.Linear2DRandom}. */ -@Deprecated(forRemoval = true, since = "TODO") +@Deprecated(forRemoval = true, since = "2.9.2") public class Linear2DBlockPattern extends AbstractPattern { private final Pattern[] patternsArray; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java index e4d3822cc..6c9d039d0 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java @@ -15,7 +15,7 @@ import static java.lang.Math.floorDiv; * @deprecated replaced by {@link com.sk89q.worldedit.function.pattern.RandomPattern} * combined with {@link com.fastasyncworldedit.core.math.random.Linear3DRandom}. */ -@Deprecated(forRemoval = true, since = "TODO") +@Deprecated(forRemoval = true, since = "2.9.2") public class Linear3DBlockPattern extends AbstractPattern { private final Pattern[] patternsArray; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear2DRandom.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear2DRandom.java index 4f039031e..04a837b72 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear2DRandom.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear2DRandom.java @@ -6,7 +6,7 @@ import static java.lang.Math.floorDiv; /** * A {@link SimpleRandom} that deterministically maps coordinates * to values. - * @since TODO + * @since 2.9.2 */ public class Linear2DRandom implements SimpleRandom { private final int xScale; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear3DRandom.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear3DRandom.java index 87f350fe4..a1ab87045 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear3DRandom.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear3DRandom.java @@ -5,7 +5,7 @@ import static java.lang.Math.floorDiv; /** * A {@link SimpleRandom} that deterministically maps coordinates * to values. - * @since TODO + * @since 2.9.2 */ public class Linear3DRandom implements SimpleRandom { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java index 83a639ead..cadc35fc8 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java @@ -59,7 +59,7 @@ public interface BlockVector3Set extends Set { * * @param x x offset * @param z z offset - * @since TODO + * @since 2.9.2 */ void setOffset(int x, int z); @@ -70,7 +70,7 @@ public interface BlockVector3Set extends Set { * @param x x offset * @param y y offset * @param z z offset - * @since TODO + * @since 2.9.2 */ void setOffset(int x, int y, int z); @@ -81,7 +81,7 @@ public interface BlockVector3Set extends Set { * @param y y radius center * @param z z radius center * @return if radius is contained by the set - * @since TODO + * @since 2.9.2 */ boolean containsRadius(int x, int y, int z, int radius); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java index e44a1c19d..69563af87 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java @@ -79,7 +79,7 @@ public interface Pattern extends Filter { * Get the likely maximum size of the volume this pattern will affect * * @return Pattern size - * @since TODO + * @since 2.9.2 */ default BlockVector3 size() { return BlockVector3.ONE; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java index 5c8655893..c76b058b1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java @@ -65,7 +65,7 @@ public enum RegionSelectorType { * Get a {@link RegionSelectorType} for the given {@link RegionSelector} * * @param selector Region selector to get type enum for - * @since TODO + * @since 2.9.2 */ @Nullable public static RegionSelectorType getForSelector(RegionSelector selector) { From a39ee6e045a28eb3f5cb83eb4fff71b79a48e8e2 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Thu, 4 Apr 2024 22:31:51 +0200 Subject: [PATCH 191/466] Back to snaptshot for development Signed-off-by: Alexander Brandes --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 8c2685561..ae8df13a5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.9.2") +var rootVersion by extra("2.9.3") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s", rootVersion) +version = String.format("%s-%s", rootVersion, buildNumber) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From 08f89b9a6976da6bd9237467a680543d66322b1b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 Apr 2024 20:32:52 +0000 Subject: [PATCH 192/466] Update plotsquared to v7.3.7 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f1c25e764..24872b49a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" towny = "0.100.2.0" -plotsquared = "7.3.6" +plotsquared = "7.3.7" # Third party bstats = "3.0.2" From 96f7ff4408711565ac1ab060385108ffe2b7c747 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 Apr 2024 23:56:33 +0000 Subject: [PATCH 193/466] Update dependency io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin to v1.5.13 --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 878f1b845..c703a6c3a 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -24,7 +24,7 @@ dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2") implementation("com.github.johnrengelman:shadow:8.1.1") - implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.12") + implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.13") } kotlin { From 58fd4ac288960351978cafef613eea3c7644c727 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:03:19 +0000 Subject: [PATCH 194/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240405.071722-146 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index e4539cd79..d0188257f 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240402.103709-145") + the().paperDevBundle("1.20.4-R0.1-20240405.071722-146") compileOnly(libs.paperlib) } From 8b597418cc9d484bd1e869c64e241d58eac13ae1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 6 Apr 2024 07:36:53 +0000 Subject: [PATCH 195/466] Update plugin io.github.gradle-nexus.publish-plugin to v2 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index ae8df13a5..8086d4bda 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ import java.time.format.DateTimeFormatter import xyz.jpenilla.runpaper.task.RunServer plugins { - id("io.github.gradle-nexus.publish-plugin") version "1.3.0" + id("io.github.gradle-nexus.publish-plugin") version "2.0.0" id("xyz.jpenilla.run-paper") version "2.2.3" } From 606e07bfdfb967d97895c5a4c8e69ec30b99dcec Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 6 Apr 2024 22:27:02 +0000 Subject: [PATCH 196/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240406.215857-153 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index d0188257f..72a2e29a3 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240405.071722-146") + the().paperDevBundle("1.20.4-R0.1-20240406.215857-153") compileOnly(libs.paperlib) } From b4c3ec3a64ca630ecce34398a951289fd7ee89bb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 7 Apr 2024 00:51:03 +0000 Subject: [PATCH 197/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240406.235646-156 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 72a2e29a3..478c29e59 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240406.215857-153") + the().paperDevBundle("1.20.4-R0.1-20240406.235646-156") compileOnly(libs.paperlib) } From d16cb8eb916ae6bf501334ebdd5bd20f9b9956f2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 7 Apr 2024 03:11:18 +0000 Subject: [PATCH 198/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240407.005218-157 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 478c29e59..888646fb0 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240406.235646-156") + the().paperDevBundle("1.20.4-R0.1-20240407.005218-157") compileOnly(libs.paperlib) } From fa6e924f567bccac4bc4288c85c8bfa455923618 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 08:03:47 +0000 Subject: [PATCH 199/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240408.052944-158 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 888646fb0..5c69ec443 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240407.005218-157") + the().paperDevBundle("1.20.4-R0.1-20240408.052944-158") compileOnly(libs.paperlib) } From ca2c18e0069a9dc5ce2a8bc012c0f91eebf4f5a5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 21:42:05 +0000 Subject: [PATCH 200/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.2.1 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 24872b49a..84eb05c9c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.2.0" +towny = "0.100.2.1" plotsquared = "7.3.7" # Third party From d0b676210b49c695ce2319d1261f2c52311f8554 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 11 Apr 2024 00:33:15 +0000 Subject: [PATCH 201/466] Update dependency io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin to v1.5.15 --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index c703a6c3a..f3058a653 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -24,7 +24,7 @@ dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2") implementation("com.github.johnrengelman:shadow:8.1.1") - implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.13") + implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.15") } kotlin { From a0ef151341016b3ae9e024dc777f0330a922bab9 Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Fri, 12 Apr 2024 20:55:40 +0200 Subject: [PATCH 202/466] Fix heightmap brush with imgur images (#2680) fix: heightmap brush with imgur / remote images --- .../core/util/MainUtil.java | 20 +++++++++++-------- .../core/util/image/ImageUtil.java | 6 +++--- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java index 41c4e5704..1c5fe044a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java @@ -554,8 +554,15 @@ public class MainUtil { } public static BufferedImage readImage(URL url) throws IOException { + try (final InputStream stream = readImageStream(url.toURI())) { + return readImage(stream); + } catch (URISyntaxException e) { + throw new IOException("failed to parse url to uri reference", e); + } + } + + public static InputStream readImageStream(final URI uri) throws IOException { try { - final URI uri = url.toURI(); HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).GET(); if (uri.getHost().equalsIgnoreCase("i.imgur.com")) { @@ -566,16 +573,13 @@ public class MainUtil { requestBuilder.build(), HttpResponse.BodyHandlers.ofInputStream() ); - try (final InputStream body = response.body()) { - if (response.statusCode() > 299) { - throw new IOException("Expected 2xx as response code, but received " + response.statusCode()); - } - return readImage(body); + final InputStream body = response.body(); + if (response.statusCode() > 299) { + throw new IOException("Expected 2xx as response code, but received " + response.statusCode()); } + return body; } catch (InterruptedException e) { throw new IOException("request was interrupted", e); - } catch (URISyntaxException e) { - throw new IOException("failed to parse url to uri reference", e); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/image/ImageUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/image/ImageUtil.java index f99a17e6f..c7c8edda3 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/image/ImageUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/image/ImageUtil.java @@ -176,8 +176,8 @@ public class ImageUtil { } public static BufferedImage load(URI uri) throws InputParseException { - try { - return MainUtil.readImage(getInputStream(uri)); + try (final InputStream stream = getInputStream(uri)) { + return MainUtil.readImage(stream); } catch (IOException e) { throw new InputParseException(TextComponent.of(e.getMessage())); } @@ -190,7 +190,7 @@ public class ImageUtil { File file = new File(uri.getPath()); return new FileInputStream(file); } - return new URL(uriStr).openStream(); + return MainUtil.readImageStream(uri); } catch (IOException e) { throw new InputParseException(TextComponent.of(e.getMessage())); } From c1e2f23f94711bb42c17b29a9eb7c6ad4ceff4f4 Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Fri, 12 Apr 2024 20:55:58 +0200 Subject: [PATCH 203/466] Fix error on adapting custom entities / entity types (#2674) chore/fix: entity type adaption, more in line with upstream --- .../bukkit/adapter/IBukkitAdapter.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IBukkitAdapter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IBukkitAdapter.java index 29162b607..9792f9344 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IBukkitAdapter.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IBukkitAdapter.java @@ -31,6 +31,8 @@ import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; import org.bukkit.TreeType; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; @@ -186,10 +188,12 @@ public interface IBukkitAdapter { } default org.bukkit.entity.EntityType adapt(EntityType entityType) { - if (!entityType.getId().startsWith("minecraft:")) { - throw new IllegalArgumentException("Bukkit only supports vanilla entities"); + NamespacedKey entityKey = NamespacedKey.fromString(entityType.toString()); + if (entityKey == null) { + throw new IllegalArgumentException("Entity key '" + entityType + "' does not map to Bukkit"); } - return org.bukkit.entity.EntityType.fromName(entityType.getId().substring(10).toLowerCase(Locale.ROOT)); + + return Registry.ENTITY_TYPE.get(entityKey); } /** @@ -343,7 +347,7 @@ public interface IBukkitAdapter { * @return WorldEdit EntityType */ default EntityType adapt(org.bukkit.entity.EntityType entityType) { - return EntityTypes.get(entityType.getName().toLowerCase(Locale.ROOT)); + return EntityTypes.get(entityType.getKey().toString()); } /** From e76904f228e6869932184abf72403cacc5ee7688 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 Apr 2024 18:56:45 +0000 Subject: [PATCH 204/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240412.173131-159 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 5c69ec443..108bce749 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240408.052944-158") + the().paperDevBundle("1.20.4-R0.1-20240412.173131-159") compileOnly(libs.paperlib) } From ed38f96f92767e93d3a6e6867bda7f1945aa398a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 Apr 2024 21:18:25 +0000 Subject: [PATCH 205/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240412.201522-163 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 108bce749..361fd380a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240412.173131-159") + the().paperDevBundle("1.20.4-R0.1-20240412.201522-163") compileOnly(libs.paperlib) } From 34dc1ddcd715a09e121c035f2d554367a10c4cad Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 13 Apr 2024 01:00:20 +0000 Subject: [PATCH 206/466] Update gradle/wrapper-validation-action action to v3 --- .github/workflows/build-pr.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/upload-release-assets.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index de239164e..0d3ffdfdd 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -11,7 +11,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v2 + uses: gradle/wrapper-validation-action@v3 - name: Setup Java uses: actions/setup-java@v4 with: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 675f0cc1c..8e80ad997 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v2 + uses: gradle/wrapper-validation-action@v3 - name: Setup Java uses: actions/setup-java@v4 with: diff --git a/.github/workflows/upload-release-assets.yml b/.github/workflows/upload-release-assets.yml index a621e9d13..b88961eb4 100644 --- a/.github/workflows/upload-release-assets.yml +++ b/.github/workflows/upload-release-assets.yml @@ -9,7 +9,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v2 + uses: gradle/wrapper-validation-action@v3 - name: Setup Java uses: actions/setup-java@v4 with: From e426e7c8ee293cdb6ba2ad4b63f2285606d016e4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 13 Apr 2024 01:00:14 +0000 Subject: [PATCH 207/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240412.212303-164 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 361fd380a..460b1a0de 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240412.201522-163") + the().paperDevBundle("1.20.4-R0.1-20240412.212303-164") compileOnly(libs.paperlib) } From 41af66e86b42ac5e1e2042563f2215d28ed0cf62 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 13 Apr 2024 20:31:18 +0000 Subject: [PATCH 208/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.2.2 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 84eb05c9c..91a96e24f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.2.1" +towny = "0.100.2.2" plotsquared = "7.3.7" # Third party From 1d79f2705a13ef19e27c9d3a56d67f6f9924aec1 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 14 Apr 2024 10:37:46 +0200 Subject: [PATCH 209/466] Update wrapper validation Signed-off-by: Alexander Brandes --- .github/workflows/build-pr.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/upload-release-assets.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index 0d3ffdfdd..fbb90ab03 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -11,7 +11,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v3 + uses: gradle/actions/wrapper-validation@v3 - name: Setup Java uses: actions/setup-java@v4 with: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8e80ad997..d6072de2f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v3 + uses: gradle/actions/wrapper-validation@v3 - name: Setup Java uses: actions/setup-java@v4 with: diff --git a/.github/workflows/upload-release-assets.yml b/.github/workflows/upload-release-assets.yml index b88961eb4..bff53a6b2 100644 --- a/.github/workflows/upload-release-assets.yml +++ b/.github/workflows/upload-release-assets.yml @@ -9,7 +9,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v3 + uses: gradle/actions/wrapper-validation@v3 - name: Setup Java uses: actions/setup-java@v4 with: From cdad55ef777b283700319f64ce054ae50a085a8f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 14 Apr 2024 11:41:30 +0000 Subject: [PATCH 210/466] Update dependency dev.notmyfault.serverlib:ServerLib to v2.3.5 --- worldedit-bukkit/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index e02685954..12c451485 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -169,7 +169,7 @@ tasks.named("shadowJar") { include(dependency("it.unimi.dsi:fastutil")) } relocate("org.incendo.serverlib", "com.fastasyncworldedit.serverlib") { - include(dependency("dev.notmyfault.serverlib:ServerLib:2.3.4")) + include(dependency("dev.notmyfault.serverlib:ServerLib:2.3.5")) } relocate("com.intellectualsites.paster", "com.fastasyncworldedit.paster") { include(dependency("com.intellectualsites.paster:Paster")) From 595a17c903cefae258a82eacfbf1c77fa8bd6d89 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 14 Apr 2024 11:41:23 +0000 Subject: [PATCH 211/466] Update dependency dev.notmyfault.serverlib:ServerLib to v2.3.5 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 91a96e24f..187a0516c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,7 +39,7 @@ commons-cli = "1.6.0" paperlib = "1.0.8" paster = "1.1.5" vault = "1.7.1" -serverlib = "2.3.4" +serverlib = "2.3.5" ## Internal text-adapter = "3.0.6" text = "3.0.4" From ccc8b15664cb1a393480dd19f0bf40c1418511cf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 14 Apr 2024 14:35:45 +0000 Subject: [PATCH 212/466] Update dependency dev.notmyfault.serverlib:ServerLib to v2.3.6 --- worldedit-bukkit/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index 12c451485..8705c931c 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -169,7 +169,7 @@ tasks.named("shadowJar") { include(dependency("it.unimi.dsi:fastutil")) } relocate("org.incendo.serverlib", "com.fastasyncworldedit.serverlib") { - include(dependency("dev.notmyfault.serverlib:ServerLib:2.3.5")) + include(dependency("dev.notmyfault.serverlib:ServerLib:2.3.6")) } relocate("com.intellectualsites.paster", "com.fastasyncworldedit.paster") { include(dependency("com.intellectualsites.paster:Paster")) From 11c09333251b13f3dbfb914201cab64b70878e6f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 14 Apr 2024 14:35:41 +0000 Subject: [PATCH 213/466] Update dependency dev.notmyfault.serverlib:ServerLib to v2.3.6 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 187a0516c..c605e3817 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,7 +39,7 @@ commons-cli = "1.6.0" paperlib = "1.0.8" paster = "1.1.5" vault = "1.7.1" -serverlib = "2.3.5" +serverlib = "2.3.6" ## Internal text-adapter = "3.0.6" text = "3.0.4" From 015b79d33309ec20eabaa3920efddac442107194 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 Apr 2024 18:10:57 +0000 Subject: [PATCH 214/466] Update dependency com.intellectualsites.paster:Paster to v1.1.6 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c605e3817..90e306b00 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -37,7 +37,7 @@ lz4-java = "1.8.0" lz4-stream = "1.0.0" commons-cli = "1.6.0" paperlib = "1.0.8" -paster = "1.1.5" +paster = "1.1.6" vault = "1.7.1" serverlib = "2.3.6" ## Internal From 7afebdbc61f9f6995d49cd669c900b843657286d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 22:27:42 +0000 Subject: [PATCH 215/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240416.195429-165 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 460b1a0de..85964a8c5 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240412.212303-164") + the().paperDevBundle("1.20.4-R0.1-20240416.195429-165") compileOnly(libs.paperlib) } From 59aa3dfdfca2421e9ac2047088c849189c05bc42 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 22:27:58 +0000 Subject: [PATCH 216/466] Update dependency me.lucko:fabric-permissions-api to v0.3 --- worldedit-fabric/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-fabric/build.gradle.kts b/worldedit-fabric/build.gradle.kts index 88f1998b4..05bf8aa1f 100644 --- a/worldedit-fabric/build.gradle.kts +++ b/worldedit-fabric/build.gradle.kts @@ -100,7 +100,7 @@ dependencies { } // No need for this at runtime - "modCompileOnly"("me.lucko:fabric-permissions-api:0.1-SNAPSHOT") + "modCompileOnly"("me.lucko:fabric-permissions-api:0.3") // Hook these up manually, because Fabric doesn't seem to quite do it properly. "compileOnly"("net.fabricmc:sponge-mixin:${project.versions.mixin}") From a3661227be3f2a34df9a5184b626002883b7883e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Apr 2024 01:10:47 +0000 Subject: [PATCH 217/466] Update dependency me.lucko:fabric-permissions-api to v0.3.1 --- worldedit-fabric/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-fabric/build.gradle.kts b/worldedit-fabric/build.gradle.kts index 05bf8aa1f..4ba08c6eb 100644 --- a/worldedit-fabric/build.gradle.kts +++ b/worldedit-fabric/build.gradle.kts @@ -100,7 +100,7 @@ dependencies { } // No need for this at runtime - "modCompileOnly"("me.lucko:fabric-permissions-api:0.3") + "modCompileOnly"("me.lucko:fabric-permissions-api:0.3.1") // Hook these up manually, because Fabric doesn't seem to quite do it properly. "compileOnly"("net.fabricmc:sponge-mixin:${project.versions.mixin}") From 1bf46c6227f0914ae6431192986f501e2e2975d0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 19 Apr 2024 06:04:34 +0000 Subject: [PATCH 218/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.2.3 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 90e306b00..d05d61861 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.2.2" +towny = "0.100.2.3" plotsquared = "7.3.7" # Third party From 341c7a5e8854f8fac08c5c5282b3891c63b67002 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 19 Apr 2024 11:20:49 +0000 Subject: [PATCH 219/466] Update plotsquared to v7.3.8 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d05d61861..3d56b9c9e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" towny = "0.100.2.3" -plotsquared = "7.3.7" +plotsquared = "7.3.8" # Third party bstats = "3.0.2" From 65fd3312325b725af78039676a1f85cba9a590a7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 19 Apr 2024 22:06:46 +0000 Subject: [PATCH 220/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240419.201130-167 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 85964a8c5..96d97d0bf 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240416.195429-165") + the().paperDevBundle("1.20.4-R0.1-20240419.201130-167") compileOnly(libs.paperlib) } From a3832515965e52ccc70ea749d9416ae74dac76b2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 20 Apr 2024 05:05:26 +0000 Subject: [PATCH 221/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240420.033107-168 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 96d97d0bf..900503d18 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240419.201130-167") + the().paperDevBundle("1.20.4-R0.1-20240420.033107-168") compileOnly(libs.paperlib) } From fdd6b86aeb6820e5f645c6cc2a36b65f53613e5e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 20 Apr 2024 18:49:33 +0000 Subject: [PATCH 222/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240420.181647-171 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 900503d18..dd0babcbd 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240420.033107-168") + the().paperDevBundle("1.20.4-R0.1-20240420.181647-171") compileOnly(libs.paperlib) } From 3dfc4f8f79b2302b2c4077c8b47a922c71aafd40 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 20 Apr 2024 21:27:10 +0000 Subject: [PATCH 223/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240420.200855-173 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index dd0babcbd..d626798e0 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240420.181647-171") + the().paperDevBundle("1.20.4-R0.1-20240420.200855-173") compileOnly(libs.paperlib) } From 1a31f39d1fad882d466ab92c47d92fbba149a60d Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 21 Apr 2024 13:16:43 +0200 Subject: [PATCH 224/466] Run renovate weekly Signed-off-by: Alexander Brandes --- .github/renovate.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/renovate.json b/.github/renovate.json index 3d0f91b5a..6b7783c42 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -2,7 +2,8 @@ "$schema" : "https://docs.renovatebot.com/renovate-schema.json", "extends" : [ "config:recommended", - ":semanticCommitsDisabled" + ":semanticCommitsDisabled", + "schedule:earlyMondays" ], "automerge" : true, "ignoreDeps" : [ From 45e18d0104b37688b177244029f5eb03d461e3a5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 28 Apr 2024 13:58:34 +0000 Subject: [PATCH 225/466] Update dependency commons-cli:commons-cli to v1.7.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3d56b9c9e..873a68c09 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -35,7 +35,7 @@ jlibnoise = "1.0.0" jchronic = "0.2.4a" lz4-java = "1.8.0" lz4-stream = "1.0.0" -commons-cli = "1.6.0" +commons-cli = "1.7.0" paperlib = "1.0.8" paster = "1.1.6" vault = "1.7.1" From b09310d745e6eeadbc7bcee4201a8efd3c9c71ae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 01:14:01 +0000 Subject: [PATCH 226/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.2.6 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 873a68c09..b4b5f642d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.2.3" +towny = "0.100.2.6" plotsquared = "7.3.8" # Third party From 3c206f44a517dfd27a054fc78f2d3b9da5cb9de0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 01:14:09 +0000 Subject: [PATCH 227/466] Update dependency paperweight-userdev to v1.20.4-R0.1-20240424.165410-174 --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index d626798e0..821b6c52d 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240420.200855-173") + the().paperDevBundle("1.20.4-R0.1-20240424.165410-174") compileOnly(libs.paperlib) } From 3310686509fcf5c9693c300b1c5d2c3d9a253c1a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 03:27:13 +0000 Subject: [PATCH 228/466] Update plugin xyz.jpenilla.run-paper to v2.2.4 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 8086d4bda..3a5d41523 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,7 +7,7 @@ import xyz.jpenilla.runpaper.task.RunServer plugins { id("io.github.gradle-nexus.publish-plugin") version "2.0.0" - id("xyz.jpenilla.run-paper") version "2.2.3" + id("xyz.jpenilla.run-paper") version "2.2.4" } if (!File("$rootDir/.git").exists()) { From 1b2e2fe12ab23903ecf84d37469689293ec0b575 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 03:27:19 +0000 Subject: [PATCH 229/466] Update dependency io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin to v1.6.2 --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index f3058a653..ad4afd071 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -24,7 +24,7 @@ dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2") implementation("com.github.johnrengelman:shadow:8.1.1") - implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.15") + implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.6.2") } kotlin { From debfabff08c829cf2eadd4130f9f7573ea10e2ac Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 1 May 2024 17:31:06 +0900 Subject: [PATCH 230/466] feat: introduce migrating config nodes to new locations (#2642) - Initial case of moving schematic limits from experimental to limits - Closes #2533 --- .../core/configuration/Config.java | 121 ++++++++++++------ .../core/configuration/Settings.java | 32 +++-- .../core/limit/FaweLimit.java | 10 ++ .../worldedit/command/SchematicCommands.java | 16 +-- 4 files changed, 123 insertions(+), 56 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java index bc300d584..c3f223dc2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java @@ -2,6 +2,7 @@ package com.fastasyncworldedit.core.configuration; import com.fastasyncworldedit.core.configuration.file.YamlConfiguration; import com.fastasyncworldedit.core.util.StringMan; +import com.sk89q.util.StringUtil; import com.sk89q.worldedit.internal.util.LogManagerCompat; import org.apache.logging.log4j.Logger; @@ -14,8 +15,10 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.invoke.MethodHandles; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; @@ -27,6 +30,9 @@ public class Config { private static final Logger LOGGER = LogManagerCompat.getLogger(); + private final Map removedKeyVals = new HashMap<>(); + private List existingMigrateNodes = null; + public Config() { save(new PrintWriter(new ByteArrayOutputStream(0)), getClass(), this, 0); } @@ -43,7 +49,8 @@ public class Config { try { return (T) field.get(instance); } catch (IllegalAccessException e) { - e.printStackTrace(); + LOGGER.error("Failed to get config option: {}", key, e); + return null; } } } @@ -67,6 +74,10 @@ public class Config { if (field.getAnnotation(Final.class) != null) { return; } + Migrate migrate = field.getAnnotation(Migrate.class); + if (existingMigrateNodes != null && migrate != null) { + existingMigrateNodes.add(migrate.value()); + } if (field.getType() == String.class && !(value instanceof String)) { value = value + ""; } @@ -74,17 +85,22 @@ public class Config { field.set(instance, value); return; } catch (Throwable e) { - e.printStackTrace(); + LOGGER.error("Failed to set config option: {}", key); } } } - LOGGER.error("Failed to set config option: {}: {} | {} | {}.yml", key, value, instance, root.getSimpleName()); + removedKeyVals.put(key, value); + LOGGER.error( + "Failed to set config option: {}: {} | {} | {}.yml. This is likely because it was removed.", + key, + value, + instance, + root.getSimpleName() + ); } public boolean load(File file) { - if (!file.exists()) { - return false; - } + existingMigrateNodes = new ArrayList<>(); YamlConfiguration yml = YamlConfiguration.loadConfiguration(file); for (String key : yml.getKeys(true)) { Object value = yml.get(key); @@ -93,6 +109,10 @@ public class Config { } set(key, value, getClass()); } + for (String node : existingMigrateNodes) { + removedKeyVals.remove(node); + } + existingMigrateNodes = null; return true; } @@ -113,7 +133,7 @@ public class Config { save(writer, getClass(), instance, 0); writer.close(); } catch (Throwable e) { - e.printStackTrace(); + LOGGER.error("Failed to save config file: {}", file, e); } } @@ -166,6 +186,19 @@ public class Config { } + /** + * Indicates that a field should be instantiated / created. + * + * @since TODO + */ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD}) + public @interface Migrate { + + String value(); + + } + @Ignore // This is not part of the config public static class ConfigBlock { @@ -222,7 +255,6 @@ public class Config { try { String CTRF = System.lineSeparator(); String spacing = StringMan.repeat(" ", indent); - HashMap, Object> instances = new HashMap<>(); for (Field field : clazz.getFields()) { if (field.getAnnotation(Ignore.class) != null) { continue; @@ -239,31 +271,14 @@ public class Config { } if (current == ConfigBlock.class) { current = (Class) ((ParameterizedType) (field.getGenericType())).getActualTypeArguments()[0]; - comment = current.getAnnotation(Comment.class); - if (comment != null) { - for (String commentLine : comment.value()) { - writer.write(spacing + "# " + commentLine + CTRF); - } - } - BlockName blockNames = current.getAnnotation(BlockName.class); - if (blockNames != null) { - writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF); - ConfigBlock configBlock = (ConfigBlock) field.get(instance); - if (configBlock == null || configBlock.getInstances().isEmpty()) { - configBlock = new ConfigBlock(); - field.set(instance, configBlock); - for (String blockName : blockNames.value()) { - configBlock.put(blockName, current.getDeclaredConstructor().newInstance()); - } - } - // Save each instance - for (Map.Entry entry : ((Map) configBlock.getRaw()).entrySet()) { - String key = entry.getKey(); - writer.write(spacing + " " + toNodeName(key) + ":" + CTRF); - save(writer, current, entry.getValue(), indent + 4); - } - } + handleConfigBlockSave(writer, instance, indent, field, spacing, CTRF, current); continue; + } else if (!removedKeyVals.isEmpty()) { + Migrate migrate = field.getAnnotation(Migrate.class); + Object value; + if (migrate != null && (value = removedKeyVals.remove(migrate.value())) != null) { + field.set(instance, value); + } } Create create = field.getAnnotation(Create.class); if (create != null) { @@ -281,7 +296,6 @@ public class Config { writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF); if (value == null) { field.set(instance, value = current.getDeclaredConstructor().newInstance()); - instances.put(current, value); } save(writer, current, value, indent + 2); } else { @@ -292,7 +306,42 @@ public class Config { } } } catch (Throwable e) { - e.printStackTrace(); + LOGGER.error("Failed to save config file", e); + } + } + + private void handleConfigBlockSave( + PrintWriter writer, + Object instance, + int indent, + Field field, + String spacing, + String CTRF, + Class current + ) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException { + Comment comment = current.getAnnotation(Comment.class); + if (comment != null) { + for (String commentLine : comment.value()) { + writer.write(spacing + "# " + commentLine + CTRF); + } + } + BlockName blockNames = current.getAnnotation(BlockName.class); + if (blockNames != null) { + writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF); + ConfigBlock configBlock = (ConfigBlock) field.get(instance); + if (configBlock == null || configBlock.getInstances().isEmpty()) { + configBlock = new ConfigBlock<>(); + field.set(instance, configBlock); + for (String blockName : blockNames.value()) { + configBlock.put(blockName, current.getDeclaredConstructor().newInstance()); + } + } + // Save each instance + for (Map.Entry entry : configBlock.getRaw().entrySet()) { + String key = entry.getKey(); + writer.write(spacing + " " + toNodeName(key) + ":" + CTRF); + save(writer, current, entry.getValue(), indent + 4); + } } } @@ -311,7 +360,7 @@ public class Config { return field; } catch (Throwable ignored) { LOGGER.warn( - "Invalid config field: {} for {}", + "Invalid config field: {} for {}. It is possible this is because it has been removed.", StringMan.join(split, "."), toNodeName(instance.getClass().getSimpleName()) ); @@ -379,7 +428,7 @@ public class Config { return null; } } catch (Throwable e) { - e.printStackTrace(); + LOGGER.error("Failed retrieving instance for config node: {}", StringUtil.joinString(split, "."), e); } return null; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index 89f48b697..8c8077d66 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -145,6 +145,14 @@ public class Settings extends Config { limit.MAX_HISTORY, newLimit.MAX_HISTORY_MB != -1 ? newLimit.MAX_HISTORY_MB : Integer.MAX_VALUE ); + limit.SCHEM_FILE_NUM_LIMIT = Math.max( + limit.SCHEM_FILE_NUM_LIMIT, + newLimit.SCHEM_FILE_NUM_LIMIT != -1 ? newLimit.SCHEM_FILE_NUM_LIMIT : Integer.MAX_VALUE + ); + limit.SCHEM_FILE_SIZE_LIMIT = Math.max( + limit.SCHEM_FILE_SIZE_LIMIT, + newLimit.SCHEM_FILE_SIZE_LIMIT != -1 ? newLimit.SCHEM_FILE_SIZE_LIMIT : Integer.MAX_VALUE + ); limit.MAX_EXPRESSION_MS = Math.max( limit.MAX_EXPRESSION_MS, newLimit.MAX_EXPRESSION_MS != -1 ? newLimit.MAX_EXPRESSION_MS : Integer.MAX_VALUE @@ -353,6 +361,18 @@ public class Settings extends Config { " - History on disk or memory will be deleted", }) public int MAX_HISTORY_MB = -1; + @Comment({ + "Sets a maximum limit (in kb) for the size of a player's schematics directory (per-player mode only)", + "Set to -1 to disable" + }) + @Migrate("experimental.per-player-file-size-limit") + public int SCHEM_FILE_SIZE_LIMIT = -1; + @Comment({ + "Sets a maximum limit for the amount of schematics in a player's schematics directory (per-player mode only)", + "Set to -1 to disable" + }) + @Migrate("experimental.per-player-file-num-limit") + public int SCHEM_FILE_NUM_LIMIT = -1; @Comment("Maximum time in milliseconds //calc can execute") public int MAX_EXPRESSION_MS = 50; @Comment({ @@ -615,18 +635,6 @@ public class Settings extends Config { }) public boolean ALLOW_TICK_FLUIDS = false; - @Comment({ - "Sets a maximum limit (in kb) for the size of a player's schematics directory (per-player mode only)", - "Set to -1 to disable" - }) - public int PER_PLAYER_FILE_SIZE_LIMIT = -1; - - @Comment({ - "Sets a maximum limit for the amount of schematics in a player's schematics directory (per-player mode only)", - "Set to -1 to disable" - }) - public int PER_PLAYER_FILE_NUM_LIMIT = -1; - } @Comment({"Web/HTTP connection related settings"}) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java index 00a47178c..e02e3abc9 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java @@ -15,6 +15,8 @@ public class FaweLimit { public int MAX_BLOCKSTATES = 0; public int MAX_ENTITIES = 0; public int MAX_HISTORY = 0; + public int SCHEM_FILE_SIZE_LIMIT = 0; + public int SCHEM_FILE_NUM_LIMIT = 0; public int MAX_EXPRESSION_MS = 0; public int INVENTORY_MODE = Integer.MAX_VALUE; public int SPEED_REDUCTION = Integer.MAX_VALUE; @@ -111,6 +113,8 @@ public class FaweLimit { MAX.MAX_BLOCKSTATES = Integer.MAX_VALUE; MAX.MAX_ENTITIES = Integer.MAX_VALUE; MAX.MAX_HISTORY = Integer.MAX_VALUE; + MAX.SCHEM_FILE_NUM_LIMIT = Integer.MAX_VALUE; + MAX.SCHEM_FILE_SIZE_LIMIT = Integer.MAX_VALUE; MAX.MAX_EXPRESSION_MS = 50; MAX.FAST_PLACEMENT = true; MAX.CONFIRM_LARGE = true; @@ -237,6 +241,8 @@ public class FaweLimit { && MAX_BLOCKSTATES == Integer.MAX_VALUE && MAX_ENTITIES == Integer.MAX_VALUE && MAX_HISTORY == Integer.MAX_VALUE + && SCHEM_FILE_SIZE_LIMIT == Integer.MAX_VALUE + && SCHEM_FILE_NUM_LIMIT == Integer.MAX_VALUE && INVENTORY_MODE == 0 && SPEED_REDUCTION == 0 && FAST_PLACEMENT @@ -256,6 +262,8 @@ public class FaweLimit { MAX_FAILS = limit.MAX_FAILS; MAX_ITERATIONS = limit.MAX_ITERATIONS; MAX_HISTORY = limit.MAX_HISTORY; + SCHEM_FILE_NUM_LIMIT = limit.SCHEM_FILE_NUM_LIMIT; + SCHEM_FILE_SIZE_LIMIT = limit.SCHEM_FILE_SIZE_LIMIT; INVENTORY_MODE = limit.INVENTORY_MODE; SPEED_REDUCTION = limit.SPEED_REDUCTION; FAST_PLACEMENT = limit.FAST_PLACEMENT; @@ -279,6 +287,8 @@ public class FaweLimit { limit.MAX_FAILS = MAX_FAILS; limit.MAX_ITERATIONS = MAX_ITERATIONS; limit.MAX_HISTORY = MAX_HISTORY; + limit.SCHEM_FILE_SIZE_LIMIT = SCHEM_FILE_SIZE_LIMIT; + limit.SCHEM_FILE_NUM_LIMIT = SCHEM_FILE_NUM_LIMIT; limit.FAST_PLACEMENT = FAST_PLACEMENT; limit.CONFIRM_LARGE = CONFIRM_LARGE; limit.RESTRICT_HISTORY_TO_REGIONS = RESTRICT_HISTORY_TO_REGIONS; 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 1158a7847..3bd62f02b 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 @@ -700,10 +700,10 @@ public class SchematicCommands { String headerBytesElem = String.format("%.1fkb", totalBytes / 1000.0); - if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT > -1) { + if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && actor.getLimit().SCHEM_FILE_SIZE_LIMIT > -1) { headerBytesElem += String.format( " / %dkb", - Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT + actor.getLimit().SCHEM_FILE_SIZE_LIMIT ); } @@ -837,7 +837,7 @@ public class SchematicCommands { //FAWE start boolean checkFilesize = Settings.settings().PATHS.PER_PLAYER_SCHEMATICS - && Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT > -1; + && actor.getLimit().SCHEM_FILE_SIZE_LIMIT > -1; double directorysizeKb = 0; String curFilepath = file.getAbsolutePath(); @@ -867,7 +867,7 @@ public class SchematicCommands { } - if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT > -1) { + if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && actor.getLimit().SCHEM_FILE_NUM_LIMIT > -1) { if (numFiles == -1) { numFiles = 0; @@ -880,7 +880,7 @@ public class SchematicCommands { } } } - int limit = Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT; + int limit = actor.getLimit().SCHEM_FILE_NUM_LIMIT; if (numFiles >= limit) { TextComponent noSlotsErr = TextComponent.of( //TODO - to be moved into captions/translatablecomponents @@ -931,7 +931,7 @@ public class SchematicCommands { if (checkFilesize) { double curKb = filesizeKb + directorysizeKb; - int allocatedKb = Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT; + int allocatedKb = actor.getLimit().SCHEM_FILE_SIZE_LIMIT; if (overwrite) { curKb -= oldKbOverwritten; @@ -966,11 +966,11 @@ public class SchematicCommands { actor.print(kbRemainingNotif); } - if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT > -1) { + if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && actor.getLimit().SCHEM_FILE_NUM_LIMIT > -1) { TextComponent slotsRemainingNotif = TextComponent.of( //TODO - to be moved into captions/translatablecomponents - "You have " + (Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT - numFiles) + "You have " + (actor.getLimit().SCHEM_FILE_NUM_LIMIT - numFiles) + " schematic file slots left.", TextColor.GRAY ); From d79bbce73a9f1f03e536e5e826e909fd093acfeb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 00:46:47 +0000 Subject: [PATCH 231/466] Update dependency org.mozilla:rhino-runtime to v1.7.15 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b4b5f642d..87bc9496b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -27,7 +27,7 @@ checkerqual = "3.42.0" truezip = "6.8.4" auto-value = "1.10.4" findbugs = "3.0.2" -rhino-runtime = "1.7.14" +rhino-runtime = "1.7.15" zstd-jni = "1.4.8-1" # Not latest as it can be difficult to obtain latest ZSTD libs antlr4 = "4.13.1" json-simple = "1.1.1" From a96b620b790477afd46754ae8706ccc78d69bb1b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 00:46:41 +0000 Subject: [PATCH 232/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.2.7 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 87bc9496b..f0db6139b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.2.6" +towny = "0.100.2.7" plotsquared = "7.3.8" # Third party From c297cd6849c2a36a0b73d83e18dda2cbc5753dc7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 03:35:14 +0000 Subject: [PATCH 233/466] Update dependency org.checkerframework:checker-qual to v3.43.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f0db6139b..a309f127c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.16.0" adventure-bukkit = "4.3.2" -checkerqual = "3.42.0" +checkerqual = "3.43.0" truezip = "6.8.4" auto-value = "1.10.4" findbugs = "3.0.2" From 991d93d8ce3f0603f9ffb5e36bcf0bf866ddac73 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 03:35:09 +0000 Subject: [PATCH 234/466] Update dependency io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin to v1.7.0 --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index ad4afd071..68ac32256 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -24,7 +24,7 @@ dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2") implementation("com.github.johnrengelman:shadow:8.1.1") - implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.6.2") + implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.0") } kotlin { From 9bc09c6a4c1e9e90344eec5671c0622a641a3e3c Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sun, 12 May 2024 10:41:48 +0200 Subject: [PATCH 235/466] Integrate WE Schematic Share system (#2619) * Integrate WE Schematic Share system (cherry picked from commit 303f5a76b2df70d63480f2126c9ef4b228eb3c59) * disable feature for now --------- Co-authored-by: Madeline Miller --- .../worldedit/command/SchematicCommands.java | 117 ++++++++++++++++-- .../util/paste/ActorCallbackPaste.java | 22 ++++ .../worldedit/util/paste/EngineHubPaste.java | 23 +++- .../worldedit/util/paste/PasteMetadata.java | 26 ++++ .../sk89q/worldedit/util/paste/Paster.java | 6 +- 5 files changed, 181 insertions(+), 13 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/PasteMetadata.java 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 3bd62f02b..e711e61ee 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -26,6 +26,7 @@ import com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder; import com.fastasyncworldedit.core.extent.clipboard.URIClipboardHolder; import com.fastasyncworldedit.core.extent.clipboard.io.schematic.MinecraftStructure; import com.fastasyncworldedit.core.util.MainUtil; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Multimap; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; @@ -60,15 +61,19 @@ import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.util.io.Closer; import com.sk89q.worldedit.util.io.file.FilenameException; import org.apache.logging.log4j.Logger; +import com.sk89q.worldedit.util.paste.EngineHubPaste; +import com.sk89q.worldedit.util.paste.PasteMetadata; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.Switch; +import org.enginehub.piston.exception.CommandException; import org.enginehub.piston.exception.StopExecutionException; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -79,9 +84,12 @@ import java.net.URISyntaxException; import java.net.URL; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Base64; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -536,6 +544,42 @@ public class SchematicCommands { .buildAndExec(worldEdit.getExecutorService()); } + @Command( + name = "share", + desc = "Share your clipboard as a schematic online" + ) + @CommandPermissions({ "worldedit.clipboard.share", "worldedit.schematic.share" }) + public void share(Actor actor, LocalSession session, + @Arg(desc = "Schematic name. Defaults to name-millis", def = "") + String schematicName, + @Arg(desc = "Format name.", def = "sponge") + String formatName) throws WorldEditException { + if (true) { + throw new UnsupportedOperationException("This feature is currently not implemented"); + } + if (worldEdit.getPlatformManager().queryCapability(Capability.GAME_HOOKS).getDataVersion() == -1) { + actor.printError(TranslatableComponent.of("worldedit.schematic.unsupported-minecraft-version")); + return; + } + + ClipboardFormat format = ClipboardFormats.findByAlias(formatName); + if (format == null) { + actor.printError(TranslatableComponent.of("worldedit.schematic.unknown-format", TextComponent.of(formatName))); + return; + } + + ClipboardHolder holder = session.getClipboard(); + + SchematicShareTask task = new SchematicShareTask(actor, format, holder, schematicName); + AsyncCommandBuilder.wrap(task, actor) + .registerWithSupervisor(worldEdit.getSupervisor(), "Sharing schematic") + .setDelayMessage(TranslatableComponent.of("worldedit.schematic.save.saving")) + .setWorkingMessage(TranslatableComponent.of("worldedit.schematic.save.still-saving")) + .onSuccess("Shared", (url -> actor.printInfo(TextComponent.of(url.toExternalForm() + ".schem").clickEvent(ClickEvent.openUrl(url.toExternalForm() + ".schem"))))) + .onFailure("Failed to share schematic", worldEdit.getPlatformManager().getPlatformCommandManager().getExceptionConverter()) + .buildAndExec(worldEdit.getExecutorService()); + } + @Command( name = "formats", aliases = {"listformats", "f"}, @@ -804,14 +848,48 @@ public class SchematicCommands { } - private static class SchematicSaveTask implements Callable { + private abstract static class SchematicOutputTask implements Callable { + protected final Actor actor; + protected final ClipboardFormat format; + protected final ClipboardHolder holder; - private final Actor actor; - private final ClipboardFormat format; - private final ClipboardHolder holder; + SchematicOutputTask( + Actor actor, + ClipboardFormat format, + ClipboardHolder holder + ) { + this.actor = actor; + this.format = format; + this.holder = holder; + } + + protected void writeToOutputStream(OutputStream outputStream) throws Exception { + Clipboard clipboard = holder.getClipboard(); + Transform transform = holder.getTransform(); + Clipboard target; + // If we have a transform, bake it into the copy + if (transform.isIdentity()) { + target = clipboard; + } else { + FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform); + target = new BlockArrayClipboard(result.getTransformedRegion()); + target.setOrigin(clipboard.getOrigin()); + Operations.completeLegacy(result.copyTo(target)); + } + + try (Closer closer = Closer.create()) { + OutputStream stream = closer.register(outputStream); + BufferedOutputStream bos = closer.register(new BufferedOutputStream(stream)); + ClipboardWriter writer = closer.register(format.getWriter(bos)); + writer.write(target); + } + } + } + + private static class SchematicSaveTask extends SchematicOutputTask { + private File file; private final boolean overwrite; private final File rootDir; - private File file; SchematicSaveTask( Actor actor, @@ -821,11 +899,9 @@ public class SchematicCommands { ClipboardHolder holder, boolean overwrite ) { - this.actor = actor; + super(actor, format, holder); this.file = file; this.rootDir = rootDir; - this.format = format; - this.holder = holder; this.overwrite = overwrite; } @@ -984,7 +1060,32 @@ public class SchematicCommands { //FAWE end return null; } + } + private static class SchematicShareTask extends SchematicOutputTask { + private final String name; + + SchematicShareTask(Actor actor, ClipboardFormat format, ClipboardHolder holder, String name) { + super(actor, format, holder); + this.name = name; + } + + @Override + public URL call() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + writeToOutputStream(baos); + } catch (Exception e) { + throw new CommandException(TextComponent.of(e.getMessage()), e, ImmutableList.of()); + } + + EngineHubPaste pasteService = new EngineHubPaste(); + PasteMetadata metadata = new PasteMetadata(); + metadata.author = this.actor.getName(); + metadata.extension = "schem"; + metadata.name = name == null ? actor.getName() + "-" + System.currentTimeMillis() : name; + return pasteService.paste(new String(Base64.getEncoder().encode(baos.toByteArray()), StandardCharsets.UTF_8), metadata).call(); + } } private static class SchematicListTask implements Callable { 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 680dbed0d..152dcfea3 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 @@ -83,4 +83,26 @@ public final class ActorCallbackPaste { .buildAndExec(Pasters.getExecutor()); } + + /** + * Submit data to a pastebin service and inform the sender of + * success or failure. + * + * @param supervisor The supervisor instance + * @param sender The sender + * @param content The content + * @param pasteMetadata The paste metadata + * @param successMessage The message builder, given the URL as an arg + */ + public static void pastebin(Supervisor supervisor, final Actor sender, String content, PasteMetadata pasteMetadata, final TranslatableComponent.Builder successMessage) { + Callable task = paster.paste(content, pasteMetadata); + + AsyncCommandBuilder.wrap(task, sender) + .registerWithSupervisor(supervisor, "Submitting content to a pastebin service.") + .setDelayMessage(TranslatableComponent.of("worldedit.pastebin.uploading")) + .onSuccess((String) null, url -> sender.printInfo(successMessage.args(TextComponent.of(url.toString())).build())) + .onFailure("Failed to submit paste", null) + .buildAndExec(Pasters.getExecutor()); + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java index f9bf84375..037cea727 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java @@ -33,23 +33,38 @@ public class EngineHubPaste implements Paster { private static final Gson GSON = new Gson(); @Override - public Callable paste(String content) { - return new PasteTask(content); + public Callable paste(String content, PasteMetadata metadata) { + return new PasteTask(content, metadata); } private static final class PasteTask implements Callable { private final String content; + private final PasteMetadata metadata; - private PasteTask(String content) { + private PasteTask(String content, PasteMetadata metadata) { this.content = content; + this.metadata = metadata; } @Override public URL call() throws IOException, InterruptedException { URL initialUrl = HttpRequest.url("https://paste.enginehub.org/signed_paste"); - SignedPasteResponse response = GSON.fromJson(HttpRequest.get(initialUrl) + HttpRequest requestBuilder = HttpRequest.get(initialUrl); + + requestBuilder.header("x-paste-meta-from", "EngineHub"); + if (metadata.name != null) { + requestBuilder.header("x-paste-meta-name", metadata.name); + } + if (metadata.author != null) { + requestBuilder.header("x-paste-meta-author", metadata.author); + } + if (metadata.extension != null) { + requestBuilder.header("x-paste-meta-extension", metadata.extension); + } + + SignedPasteResponse response = GSON.fromJson(requestBuilder .execute() .expectResponseCode(200) .returnContent() diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/PasteMetadata.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/PasteMetadata.java new file mode 100644 index 000000000..5654e6ae5 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/PasteMetadata.java @@ -0,0 +1,26 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util.paste; + +public class PasteMetadata { + public String name; + public String extension; + public String author; +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/Paster.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/Paster.java index 0b7652b91..ccd5780b0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/Paster.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/Paster.java @@ -24,6 +24,10 @@ import java.util.concurrent.Callable; public interface Paster { - Callable paste(String content); + default Callable paste(String content) { + return paste(content, new PasteMetadata()); + } + + Callable paste(String content, PasteMetadata metadata); } From 1d9e8b60abd630854f2b72affbb58abc7c50dba2 Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 12 May 2024 11:05:00 +0100 Subject: [PATCH 236/466] fix: add missing blocktypes and some minor cleanup (#2722) - fixes #2713 --- .../worldedit/world/block/BlockTypes.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) 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 4b3204be4..513a00557 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 @@ -483,6 +483,10 @@ public final class BlockTypes { @Nullable public static final BlockType COPPER_GRATE = init(); @Nullable + public static final BlockType COPPER_ORE = init(); + @Nullable + public static final BlockType COPPER_TRAPDOOR = init(); + @Nullable public static final BlockType CORNFLOWER = init(); @Nullable public static final BlockType CRACKED_DEEPSLATE_BRICKS = init(); @@ -495,6 +499,8 @@ public final class BlockTypes { @Nullable public static final BlockType CRACKED_STONE_BRICKS = init(); @Nullable + public static final BlockType CRAFTER = init(); + @Nullable public static final BlockType CRAFTING_TABLE = init(); @Nullable public static final BlockType CREEPER_HEAD = init(); @@ -685,8 +691,6 @@ public final class BlockTypes { @Nullable public static final BlockType DEEPSLATE_COPPER_ORE = init(); @Nullable - public static final BlockType COPPER_TRAPDOOR = init(); - @Nullable public static final BlockType DEEPSLATE_DIAMOND_ORE = init(); @Nullable public static final BlockType DEEPSLATE_EMERALD_ORE = init(); @@ -747,8 +751,6 @@ public final class BlockTypes { @Nullable public static final BlockType ENDER_CHEST = init(); @Nullable - public static final BlockType EXPOSED_CHISELED_COPPER = init(); - @Nullable public static final BlockType END_GATEWAY = init(); @Nullable public static final BlockType END_PORTAL = init(); @@ -767,6 +769,8 @@ public final class BlockTypes { @Nullable public static final BlockType END_STONE_BRICK_WALL = init(); @Nullable + public static final BlockType EXPOSED_CHISELED_COPPER = init(); + @Nullable public static final BlockType EXPOSED_COPPER = init(); @Nullable public static final BlockType EXPOSED_COPPER_BULB = init(); @@ -836,6 +840,9 @@ public final class BlockTypes { public static final BlockType GRASS = init(); @Nullable public static final BlockType GRASS_BLOCK = init(); + @Deprecated + @Nullable + public static final BlockType GRASS_PATH = init(); @Nullable public static final BlockType GRAVEL = init(); @Nullable @@ -925,8 +932,6 @@ public final class BlockTypes { @Nullable public static final BlockType INFESTED_CRACKED_STONE_BRICKS = init(); @Nullable - public static final BlockType CRAFTER = init(); - @Nullable public static final BlockType INFESTED_DEEPSLATE = init(); @Nullable public static final BlockType INFESTED_MOSSY_STONE_BRICKS = init(); @@ -1954,10 +1959,12 @@ public final class BlockTypes { @Nullable public static final BlockType TWISTING_VINES = init(); @Nullable - public static final BlockType VERDANT_FROGLIGHT = init(); - @Nullable public static final BlockType TWISTING_VINES_PLANT = init(); @Nullable + public static final BlockType VAULT = init(); + @Nullable + public static final BlockType VERDANT_FROGLIGHT = init(); + @Nullable public static final BlockType VINE = init(); @Nullable public static final BlockType VOID_AIR = init(); @@ -2026,7 +2033,7 @@ public final class BlockTypes { public static final BlockType WAXED_CUT_COPPER_SLAB = init(); @Nullable public static final BlockType WAXED_CUT_COPPER_STAIRS = init(); - @ Nullable + @Nullable public static final BlockType WAXED_EXPOSED_CHISELED_COPPER = init(); @Nullable public static final BlockType WAXED_EXPOSED_COPPER = init(); From 69dbf760a84c33ce90be8600adcf7568195e8615 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 01:53:18 +0000 Subject: [PATCH 237/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.2.8 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a309f127c..99f1ff6fc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.2.7" +towny = "0.100.2.8" plotsquared = "7.3.8" # Third party From ae4d0236cc4c7f8ef899bae600c5f180a507703e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 01:53:27 +0000 Subject: [PATCH 238/466] Update dependency io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin to v1.7.1 --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 68ac32256..ef4a18fe7 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -24,7 +24,7 @@ dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2") implementation("com.github.johnrengelman:shadow:8.1.1") - implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.0") + implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.1") } kotlin { From c9b2f441c1837df0e68031d5f122a9521cf5d188 Mon Sep 17 00:00:00 2001 From: Jordan Date: Tue, 14 May 2024 20:30:34 +0100 Subject: [PATCH 239/466] feat: only unstuck a player if configured to do so (#2723) - also add unstuck to a couple of other commands - closes #2675 --- .../core/configuration/Settings.java | 11 +++++++++++ .../worldedit/command/GenerationCommands.java | 14 ++++++++++---- .../sk89q/worldedit/command/RegionCommands.java | 6 +++++- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index 8c8077d66..63f37fd6b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -79,6 +79,8 @@ public class Settings extends Config { @Create public REGION_RESTRICTIONS_OPTIONS REGION_RESTRICTIONS_OPTIONS; @Create + public GENERAL GENERAL; + @Create public ConfigBlock LIMITS; private Settings() { @@ -752,4 +754,13 @@ public class Settings extends Config { } + public static class GENERAL { + + @Comment({ + "If the player should be relocated/unstuck when a generation command would bury them", + }) + public boolean UNSTUCK_ON_GENERATE = true; + + } + } 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 dbd698b24..d3d456965 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 @@ -184,6 +184,9 @@ public class GenerationCommands { BlockVector3 pos = session.getPlacementPosition(actor); int affected = editSession.makeCylinder(pos, pattern, radiusX, radiusZ, height, !hollow); + if (actor instanceof Player && Settings.settings().GENERAL.UNSTUCK_ON_GENERATE) { + ((Player) actor).findFreePosition(); + } actor.print(Caption.of("worldedit.cyl.created", TextComponent.of(affected))); return affected; } @@ -227,6 +230,9 @@ public class GenerationCommands { BlockVector3 pos = session.getPlacementPosition(actor); int affected = editSession.makeCone(pos, pattern, radiusX, radiusZ, height, !hollow, thickness); + if (actor instanceof Player && Settings.settings().GENERAL.UNSTUCK_ON_GENERATE) { + ((Player) actor).findFreePosition(); + } actor.printInfo(Caption.of("worldedit.cone.created", TextComponent.of(affected))); return affected; } @@ -293,7 +299,7 @@ public class GenerationCommands { } int affected = editSession.makeSphere(pos, pattern, radiusX, radiusY, radiusZ, !hollow); - if (actor instanceof Player) { + if (actor instanceof Player && Settings.settings().GENERAL.UNSTUCK_ON_GENERATE) { ((Player) actor).findFreePosition(); } actor.print(Caption.of("worldedit.sphere.created", TextComponent.of(affected))); @@ -379,7 +385,7 @@ public class GenerationCommands { worldEdit.checkMaxRadius(size); BlockVector3 pos = session.getPlacementPosition(actor); int affected = editSession.makePyramid(pos, pattern, size, !hollow); - if (actor instanceof Player) { + if (actor instanceof Player && Settings.settings().GENERAL.UNSTUCK_ON_GENERATE) { ((Player) actor).findFreePosition(); } actor.print(Caption.of("worldedit.pyramid.created", TextComponent.of(affected))); @@ -457,7 +463,7 @@ public class GenerationCommands { hollow, session.getTimeout() ); - if (actor instanceof Player) { + if (actor instanceof Player && Settings.settings().GENERAL.UNSTUCK_ON_GENERATE) { ((Player) actor).findFreePosition(); } actor.print(Caption.of("worldedit.generate.created", TextComponent.of(affected))); @@ -741,7 +747,7 @@ public class GenerationCommands { radius.divide(max), sphericity / 100 ); - if (actor instanceof Player) { + if (actor instanceof Player && Settings.settings().GENERAL.UNSTUCK_ON_GENERATE) { ((Player) actor).findFreePosition(); } actor.print(Caption.of("worldedit.sphere.created", TextComponent.of(affected))); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index a72cba4b3..73cb34274 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 @@ -22,6 +22,7 @@ package com.sk89q.worldedit.command; import com.fastasyncworldedit.core.FaweAPI; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; import com.fastasyncworldedit.core.limit.FaweLimit; import com.fastasyncworldedit.core.util.MaskTraverser; @@ -715,6 +716,9 @@ public class RegionCommands { session.setSourceMask(mask); //FAWE end } + if (actor instanceof Player && Settings.settings().GENERAL.UNSTUCK_ON_GENERATE) { + ((Player) actor).findFreePosition(); + } if (success) { actor.print(Caption.of("worldedit.regen.regenerated")); } else { @@ -788,7 +792,7 @@ public class RegionCommands { String.join(" ", expression), session.getTimeout() ); - if (actor instanceof Player) { + if (actor instanceof Player && Settings.settings().GENERAL.UNSTUCK_ON_GENERATE) { ((Player) actor).findFreePosition(); } actor.print(Caption.of("worldedit.deform.deformed", TextComponent.of(affected))); From a353c12df017bc810748a90fa6c113737db32ead Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sun, 19 May 2024 13:32:18 +0200 Subject: [PATCH 240/466] Support for 1.20.5/6 (#2721) * 1.20.6 Signed-off-by: Alexander Brandes * work Signed-off-by: Alexander Brandes * More work Signed-off-by: Alexander Brandes * chore: address more removed fields and methods, make it run * chore: don't allocate unnecessary arrays (by maps) * chore: the comment might still be noteworthy * chore: no need to synchronize twice * fix obfuscation changes * remove unneeded deprecation * make regen work without throwing exceptions - but slow * fix: error when adapting BaseItemStacks without nbt * fix annoying paper api breakage --------- Signed-off-by: Alexander Brandes Co-authored-by: Alexander Brandes Co-authored-by: Pierre Maurice Schwang --- .github/ISSUE_TEMPLATE/bug_report.yml | 3 +- .github/workflows/build-pr.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/upload-release-assets.yml | 2 +- COMPILING.adoc | 6 +- Jenkinsfile | 2 +- build.gradle.kts | 2 +- buildSrc/build.gradle.kts | 14 +- buildSrc/src/main/kotlin/CommonConfig.kt | 2 +- buildSrc/src/main/kotlin/CommonJavaConfig.kt | 4 +- buildSrc/src/main/kotlin/LibsConfig.kt | 4 +- gradle/libs.versions.toml | 2 +- settings.gradle.kts | 2 +- .../v1_20_R3/PaperweightPlatformAdapter.java | 1 - .../build.gradle.kts | 4 +- .../v1_20_R4}/PaperweightAdapter.java | 458 ++++--- .../v1_20_R4}/PaperweightDataConverters.java | 1114 +++++++---------- .../v1_20_R4}/PaperweightFakePlayer.java | 27 +- .../PaperweightWorldNativeAccess.java | 61 +- .../v1_20_R4}/PaperweightBlockMaterial.java | 53 +- .../v1_20_R4}/PaperweightFaweAdapter.java | 181 ++- .../PaperweightFaweWorldNativeAccess.java | 17 +- .../fawe/v1_20_R4}/PaperweightGetBlocks.java | 123 +- .../v1_20_R4}/PaperweightGetBlocks_Copy.java | 26 +- .../v1_20_R4}/PaperweightMapChunkUtil.java | 8 +- .../v1_20_R4}/PaperweightPlatformAdapter.java | 186 ++- .../v1_20_R4}/PaperweightPostProcessor.java | 2 +- .../PaperweightStarlightRelighter.java | 8 +- .../PaperweightStarlightRelighterFactory.java | 4 +- .../nbt/PaperweightLazyCompoundTag.java | 2 +- .../v1_20_R4}/regen/PaperweightRegen.java | 252 ++-- worldedit-bukkit/build.gradle.kts | 3 +- .../bukkit/adapter/Regenerator.java | 130 +- .../bukkit/listener/ChunkListener.java | 2 +- .../bukkit/util/CommandRegistration.java | 8 +- worldedit-core/doctools/build.gradle.kts | 6 +- .../sk89q/worldedit/WorldEditManifest.java | 5 +- .../sk89q/worldedit/entity/BaseEntity.java | 2 + .../extent/validation/BlockChangeLimiter.java | 1 + .../util/io/ForwardSeekableInputStream.java | 8 +- .../sk89q/worldedit/util/net/HttpRequest.java | 10 +- .../worldedit/util/paste/EngineHubPaste.java | 3 +- .../util/task/FutureForwardingTask.java | 13 +- .../world/block/BlockCategories.java | 9 + .../worldedit/world/block/BlockType.java | 1 + .../worldedit/world/block/BlockTypes.java | 2 + .../worldedit/world/chunk/AnvilChunk13.java | 2 +- .../worldedit/world/entity/EntityTypes.java | 8 + .../worldedit/world/item/ItemCategories.java | 54 +- .../sk89q/worldedit/world/item/ItemType.java | 4 +- .../sk89q/worldedit/world/item/ItemTypes.java | 39 + 52 files changed, 1527 insertions(+), 1359 deletions(-) rename worldedit-bukkit/adapters/{adapter-1_18_2 => adapter-1_20_5}/build.gradle.kts (78%) rename worldedit-bukkit/adapters/{adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2 => adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4}/PaperweightAdapter.java (77%) rename worldedit-bukkit/adapters/{adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2 => adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4}/PaperweightDataConverters.java (94%) rename worldedit-bukkit/adapters/{adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2 => adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4}/PaperweightFakePlayer.java (78%) rename worldedit-bukkit/adapters/{adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2 => adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4}/PaperweightWorldNativeAccess.java (74%) rename worldedit-bukkit/adapters/{adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2 => adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4}/PaperweightBlockMaterial.java (69%) rename worldedit-bukkit/adapters/{adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2 => adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4}/PaperweightFaweAdapter.java (82%) rename worldedit-bukkit/adapters/{adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2 => adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4}/PaperweightFaweWorldNativeAccess.java (94%) rename worldedit-bukkit/adapters/{adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2 => adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4}/PaperweightGetBlocks.java (94%) rename worldedit-bukkit/adapters/{adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2 => adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4}/PaperweightGetBlocks_Copy.java (86%) rename worldedit-bukkit/adapters/{adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2 => adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4}/PaperweightMapChunkUtil.java (88%) rename worldedit-bukkit/adapters/{adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2 => adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4}/PaperweightPlatformAdapter.java (80%) rename worldedit-bukkit/adapters/{adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2 => adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4}/PaperweightPostProcessor.java (99%) rename worldedit-bukkit/adapters/{adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2 => adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4}/PaperweightStarlightRelighter.java (90%) rename worldedit-bukkit/adapters/{adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2 => adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4}/PaperweightStarlightRelighterFactory.java (88%) rename worldedit-bukkit/adapters/{adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2 => adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4}/nbt/PaperweightLazyCompoundTag.java (98%) rename worldedit-bukkit/adapters/{adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2 => adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4}/regen/PaperweightRegen.java (69%) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index bc78076bd..1de1aa8df 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -27,10 +27,9 @@ body: description: Which server version version you using? If your server version is not listed, it is not supported. Update to a supported version first. multiple: false options: - - '1.20.4' + - '1.20.5/6' - '1.20' - '1.19.4' - - '1.18.2' validations: required: true diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index fbb90ab03..e6ad24a7f 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -17,7 +17,7 @@ jobs: with: distribution: temurin cache: gradle - java-version: 17 + java-version: 21 - name: Build on ${{ matrix.os }} run: ./gradlew build -s - name: Archive artifacts diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d6072de2f..5b44758dd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,7 +17,7 @@ jobs: with: distribution: temurin cache: gradle - java-version: 17 + java-version: 21 - name: Clean Build run: ./gradlew clean build --no-daemon - name: Determine release status diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b7e9c61ed..0cd6f4443 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -25,7 +25,7 @@ jobs: with: distribution: temurin cache: gradle - java-version: 17 + java-version: 21 - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: diff --git a/.github/workflows/upload-release-assets.yml b/.github/workflows/upload-release-assets.yml index bff53a6b2..22d6c6083 100644 --- a/.github/workflows/upload-release-assets.yml +++ b/.github/workflows/upload-release-assets.yml @@ -15,7 +15,7 @@ jobs: with: distribution: temurin cache: gradle - java-version: 17 + java-version: 21 - name: Clean Build run: ./gradlew clean build --no-daemon - name: Upload Release Assets diff --git a/COMPILING.adoc b/COMPILING.adoc index 87b21b685..bdd30ba62 100644 --- a/COMPILING.adoc +++ b/COMPILING.adoc @@ -3,12 +3,12 @@ = Compiling -You can compile FastAsyncWorldEdit as long as you have some version of Java greater than or equal to 17 installed. Gradle will download JDK 17 specifically if needed, +You can compile FastAsyncWorldEdit as long as you have some version of Java greater than or equal to 21 installed. Gradle will download JDK 21 specifically if needed, but it needs some version of Java to bootstrap from. -Note that if you have JRE 8 installed, Gradle will currently attempt to use that to compile, which will not work. It is easiest to uninstall JRE 8 and replace it with JDK 17. +Note that if you have JRE 8 installed, Gradle will currently attempt to use that to compile, which will not work. It is easiest to uninstall JRE 8 and replace it with JDK 21. -You can get the JDK 17 link:https://adoptium.net/[here] from Adoptium. +You can get the JDK 21 link:https://adoptium.net/[here] from Adoptium. The build process uses Gradle, which you do *not* need to download. FastAsyncWorldEdit is a multi-module project with three active modules: diff --git a/Jenkinsfile b/Jenkinsfile index 61000e9fb..94db4eda2 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -7,7 +7,7 @@ pipeline { stage('Build') { steps { withEnv([ - "PATH+JAVA=${tool 'Temurin-17.0.7_7'}/bin" + "PATH+JAVA=${tool 'Temurin-21.0.3_9'}/bin" ]) { sh './gradlew clean build' } diff --git a/build.gradle.kts b/build.gradle.kts index 3a5d41523..aed748cdb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -83,7 +83,7 @@ allprojects { } applyCommonConfiguration() -val supportedVersions = listOf("1.18.2", "1.19.4", "1.20", "1.20.4") +val supportedVersions = listOf("1.19.4", "1.20", "1.20.4", "1.20.5", "1.20.6") tasks { supportedVersions.forEach { diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index ef4a18fe7..f116fd23e 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -25,10 +25,22 @@ dependencies { implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2") implementation("com.github.johnrengelman:shadow:8.1.1") implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.1") + constraints { + val asmVersion = "[9.7,)" + implementation("org.ow2.asm:asm:$asmVersion") { + because("Need Java 21 support in shadow") + } + implementation("org.ow2.asm:asm-commons:$asmVersion") { + because("Need Java 21 support in shadow") + } + implementation("org.vafer:jdependency:[2.10,)") { + because("Need Java 21 support in shadow") + } + } } kotlin { jvmToolchain { - (this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(17)) + (this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(21)) } } diff --git a/buildSrc/src/main/kotlin/CommonConfig.kt b/buildSrc/src/main/kotlin/CommonConfig.kt index 6a6d552aa..e8fd3db87 100644 --- a/buildSrc/src/main/kotlin/CommonConfig.kt +++ b/buildSrc/src/main/kotlin/CommonConfig.kt @@ -33,7 +33,7 @@ fun Project.applyCommonConfiguration() { plugins.withId("java") { the().toolchain { - languageVersion.set(JavaLanguageVersion.of(17)) + languageVersion.set(JavaLanguageVersion.of(21)) } } diff --git a/buildSrc/src/main/kotlin/CommonJavaConfig.kt b/buildSrc/src/main/kotlin/CommonJavaConfig.kt index 8a111a2e7..f915c2e0c 100644 --- a/buildSrc/src/main/kotlin/CommonJavaConfig.kt +++ b/buildSrc/src/main/kotlin/CommonJavaConfig.kt @@ -21,7 +21,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean .matching { it.name == "compileJava" || it.name == "compileTestJava" } .configureEach { val disabledLint = listOf( - "processing", "path", "fallthrough", "serial" + "processing", "path", "fallthrough", "serial", "overloads", "this-escape", ) options.release.set(17) options.compilerArgs.addAll(listOf("-Xlint:all") + disabledLint.map { "-Xlint:-$it" }) @@ -31,7 +31,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean } configurations.all { - attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) + attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21) } tasks.withType().configureEach { diff --git a/buildSrc/src/main/kotlin/LibsConfig.kt b/buildSrc/src/main/kotlin/LibsConfig.kt index 5d6e7892b..2c957880a 100644 --- a/buildSrc/src/main/kotlin/LibsConfig.kt +++ b/buildSrc/src/main/kotlin/LibsConfig.kt @@ -122,7 +122,7 @@ fun Project.applyLibrariesConfiguration() { attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY)) attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED)) attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements.JAR)) - attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) + attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21) } outgoing.artifact(tasks.named("jar")) } @@ -137,7 +137,7 @@ fun Project.applyLibrariesConfiguration() { attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY)) attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED)) attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements.JAR)) - attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) + attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21) } outgoing.artifact(tasks.named("jar")) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 99f1ff6fc..c02ba9098 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] # Minecraft expectations -paper = "1.20.4-R0.1-SNAPSHOT" +paper = "1.20.6-R0.1-SNAPSHOT" fastutil = "8.5.9" guava = "31.1-jre" log4j = "2.19.0" diff --git a/settings.gradle.kts b/settings.gradle.kts index 74cba1396..48318b908 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,7 +2,7 @@ rootProject.name = "FastAsyncWorldEdit" include("worldedit-libs") -listOf("1_18_2", "1_19_4", "1_20", "1_20_2", "1_20_4").forEach { +listOf("1_19_4", "1_20", "1_20_2", "1_20_4", "1_20_5").forEach { include("worldedit-bukkit:adapters:adapter-$it") } diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java index 147ec5be7..23de00ade 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java @@ -58,7 +58,6 @@ import net.minecraft.world.level.entity.PersistentEntitySectionManager; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_20_R3.CraftChunk; -import sun.misc.Unsafe; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts similarity index 78% rename from worldedit-bukkit/adapters/adapter-1_18_2/build.gradle.kts rename to worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts index 3713af207..e1a518cbb 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts @@ -11,7 +11,7 @@ repositories { } dependencies { - // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.18.2-R0.1-SNAPSHOT - the().paperDevBundle("1.18.2-R0.1-20220920.010157-167") + // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/ + the().paperDevBundle("1.20.6-R0.1-20240516.001739-55") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java similarity index 77% rename from worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2/PaperweightAdapter.java rename to worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java index 1edc3be1d..e629c4611 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java @@ -17,24 +17,23 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R2; +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R4; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.util.concurrent.Futures; -import com.mojang.datafixers.util.Either; +import com.mojang.serialization.Codec; import com.mojang.serialization.Lifecycle; +import com.sk89q.jnbt.NBTConstants; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.PaperweightPlatformAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extent.Extent; @@ -81,14 +80,20 @@ import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.item.ItemType; import net.minecraft.Util; import net.minecraft.core.BlockPos; -import net.minecraft.core.Registry; +import net.minecraft.core.Holder; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.Tag; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkResult; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.progress.ChunkProgressListener; @@ -112,10 +117,10 @@ import net.minecraft.world.level.block.entity.StructureBlockEntity; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.DirectionProperty; import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.WorldGenSettings; +import net.minecraft.world.level.levelgen.WorldOptions; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PrimaryLevelData; import net.minecraft.world.phys.BlockHitResult; @@ -124,13 +129,13 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World.Environment; import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_18_R2.CraftServer; -import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.generator.ChunkGenerator; @@ -155,7 +160,6 @@ import java.util.Set; import java.util.TreeMap; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.concurrent.ForkJoinPool; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -166,33 +170,28 @@ import static com.google.common.base.Preconditions.checkState; public final class PaperweightAdapter implements BukkitImplAdapter { - private static final Set SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( - SideEffect.NEIGHBORS, - SideEffect.LIGHTING, - SideEffect.VALIDATION, - SideEffect.ENTITY_AI, - SideEffect.EVENTS, - SideEffect.UPDATE - ); + private static final Codec COMPONENTS_CODEC = DataComponentPatch.CODEC.optionalFieldOf( + "components", DataComponentPatch.EMPTY + ).codec(); + + private final Logger logger = Logger.getLogger(getClass().getCanonicalName()); + private final Field serverWorldsField; private final Method getChunkFutureMethod; private final Field chunkProviderExecutorField; - private final Logger LOGGER = Logger.getLogger(getClass().getCanonicalName()); + private final Watchdog watchdog; // ------------------------------------------------------------------------ // Code that may break between versions of Minecraft // ------------------------------------------------------------------------ - private final Watchdog watchdog; - private final LoadingCache fakePlayers - = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); public PaperweightAdapter() throws NoSuchFieldException, NoSuchMethodException { // A simple test CraftServer.class.cast(Bukkit.getServer()); int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); - if (dataVersion != 2975) { - throw new UnsupportedClassVersionError("Not 1.18.2!"); + if (dataVersion != 3837 && dataVersion != 3839) { + throw new UnsupportedClassVersionError("Not 1.20.(5/6)!"); } serverWorldsField = CraftServer.class.getDeclaredField("worlds"); @@ -209,7 +208,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter> biomeTypeToNMSCache = new HashMap<>(); + private static final HashMap, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); + @Override public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightWorldNativeAccess( - this, - new WeakReference<>(((CraftWorld) world).getHandle()) - ); + return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle())); + } + + private static net.minecraft.core.Direction adapt(Direction face) { + switch (face) { + case NORTH: + return net.minecraft.core.Direction.NORTH; + case SOUTH: + return net.minecraft.core.Direction.SOUTH; + case WEST: + return net.minecraft.core.Direction.WEST; + case EAST: + return net.minecraft.core.Direction.EAST; + case DOWN: + return net.minecraft.core.Direction.DOWN; + case UP: + default: + return net.minecraft.core.Direction.UP; + } } @SuppressWarnings({"rawtypes", "unchecked"}) @@ -429,16 +446,19 @@ public final class PaperweightAdapter implements BukkitImplAdapter (CompoundBinaryTag) toNativeBinary(tag)) ); - //FAWE end } @Nullable @@ -471,6 +491,22 @@ public final class PaperweightAdapter implements BukkitImplAdapter> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { - @Override - public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else if (state instanceof DirectionProperty) { - return new DirectionalProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - return new EnumProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else { - throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state.getClass().getSimpleName()); - } - } - }); + private static final LoadingCache> PROPERTY_CACHE = CacheBuilder + .newBuilder() + .build(new CacheLoader>() { + @Override + public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { + if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else if (state instanceof DirectionProperty) { + return new DirectionalProperty( + state.getName(), + (List) state + .getPossibleValues() + .stream() + .map(e -> Direction.valueOf(((StringRepresentable) e) + .getSerializedName() + .toUpperCase(Locale.ROOT))) + .collect(Collectors.toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + return new EnumProperty( + state.getName(), + (List) state + .getPossibleValues() + .stream() + .map(e -> ((StringRepresentable) e).getSerializedName()) + .collect(Collectors.toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else { + throw new IllegalArgumentException("WorldEdit needs an update to support " + state + .getClass() + .getSimpleName()); + } + } + }); - @SuppressWarnings({ "rawtypes" }) + @SuppressWarnings({"rawtypes"}) @Override public Map> getProperties(BlockType blockType) { Map> properties = new TreeMap<>(); @@ -520,50 +574,68 @@ public final class PaperweightAdapter implements BukkitImplAdapter CompoundTag @Override public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { - ((CraftPlayer) player).getHandle().networkManager.send(ClientboundBlockEntityDataPacket.create( - new StructureBlockEntity( - new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()), - Blocks.STRUCTURE_BLOCK.defaultBlockState() - ), - __ -> (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) + var structureBlock = new StructureBlockEntity( + new BlockPos(pos.getX(), pos.getY(), pos.getZ()), + Blocks.STRUCTURE_BLOCK.defaultBlockState() + ); + structureBlock.setLevel(((CraftPlayer) player).getHandle().level()); + ((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create( + structureBlock, + (blockEntity, registryAccess) -> (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) )); } - //FAWE end @Override public void sendFakeOP(Player player) { - ((CraftPlayer) player).getHandle().networkManager.send(new ClientboundEntityEventPacket( + ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( ((CraftPlayer) player).getHandle(), (byte) 28 )); } @Override public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { - ItemStack stack = new ItemStack(Registry.ITEM.get(ResourceLocation.tryParse(item.getType().getId())), item.getAmount()); - stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData()))); + final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess(); + ItemStack stack = new ItemStack( + registryAccess.registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().getId())), + item.getAmount() + ); + final CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData()); + final DataComponentPatch patch = COMPONENTS_CODEC + .parse(registryAccess.createSerializationContext(NbtOps.INSTANCE), nbt) + .getOrThrow(); + stack.applyComponents(patch); return CraftItemStack.asCraftMirror(stack); } @Override public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { + final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess(); final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); - final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); - //FAWE start - CBT > CT - weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); - //FAWE end - return weStack; + final Tag tag = COMPONENTS_CODEC.encodeStart( + registryAccess.createSerializationContext(NbtOps.INSTANCE), + nmsStack.getComponentsPatch() + ).getOrThrow(); + return new BaseItemStack( + BukkitAdapter.asItemType(itemStack.getType()), + LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag)), + itemStack.getAmount() + ); } + private final LoadingCache fakePlayers + = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); + @Override public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) { CraftWorld craftWorld = (CraftWorld) world; ServerLevel worldServer = craftWorld.getHandle(); - ItemStack stack = CraftItemStack.asNMSCopy(BukkitAdapter.adapt(item instanceof BaseItemStack - ? ((BaseItemStack) item) : new BaseItemStack(item.getType(), item.getNbtData(), 1))); - stack.setTag((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData())); + ItemStack stack = CraftItemStack.asNMSCopy(adapt( + item instanceof BaseItemStack + ? ((BaseItemStack) item) + : new BaseItemStack(item.getType(), item.getNbtReference(), 1) + )); PaperweightFakePlayer fakePlayer; try { @@ -572,20 +644,20 @@ public final class PaperweightAdapter implements BukkitImplAdapter worldDimKey = getWorldDimKey(env); try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() .getWorldData().overworldData(); - WorldGenSettings originalOpts = levelProperties.worldGenSettings(); + WorldOptions originalOpts = levelProperties.worldGenOptions(); long seed = options.getSeed().orElse(originalWorld.getSeed()); - WorldGenSettings newOpts = options.getSeed().isPresent() - ? originalOpts.withSeed(levelProperties.isHardcore(), OptionalLong.of(seed)) + WorldOptions newOpts = options.getSeed().isPresent() + ? originalOpts.withSeed(OptionalLong.of(seed)) : originalOpts; LevelSettings newWorldSettings = new LevelSettings( @@ -642,23 +714,40 @@ public final class PaperweightAdapter implements BukkitImplAdapter>) + ((CompletableFuture>) getChunkFutureMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) - .thenApply(either -> either.left().orElse(null)) + .thenApply(either -> either.orElse(null)) ); } catch (IllegalAccessException | InvocationTargetException e) { throw new IllegalStateException("Couldn't load chunk for regen.", e); @@ -769,6 +856,15 @@ public final class PaperweightAdapter implements BukkitImplAdapter SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( + SideEffect.NEIGHBORS, + SideEffect.LIGHTING, + SideEffect.VALIDATION, + SideEffect.ENTITY_AI, + SideEffect.EVENTS, + SideEffect.UPDATE + ); + @Override public Set getSupportedSideEffects() { return SUPPORTED_SIDE_EFFECTS; @@ -797,7 +893,6 @@ public final class PaperweightAdapter implements BukkitImplAdapter values = ListBinaryTag.builder(); + ListBinaryTag.Builder values = ListBinaryTag.builder(); for (net.minecraft.nbt.Tag tag : foreign) { values.add(toNativeBinary(tag)); @@ -895,8 +990,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter. */ -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R2; +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R4; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -29,18 +29,21 @@ 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; import com.mojang.datafixers.DSL.TypeReference; import com.mojang.datafixers.DataFixer; import com.mojang.datafixers.DataFixerBuilder; import com.mojang.datafixers.schemas.Schema; import com.mojang.serialization.Dynamic; +import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R4.PaperweightAdapter; import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import net.minecraft.core.Direction; import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.StringTag; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; -import net.minecraft.network.chat.TextComponent; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; import net.minecraft.util.GsonHelper; import net.minecraft.util.StringUtil; import net.minecraft.util.datafix.DataFixers; @@ -66,252 +69,19 @@ 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({"rawtypes", "unchecked"}) -class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { +@SuppressWarnings({ "rawtypes", "unchecked" }) +public class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { - private static final NbtOps OPS_NBT = NbtOps.INSTANCE; - private static final int LEGACY_VERSION = 1343; - private static final Map DFU_TO_LEGACY = new HashMap<>(); - private static final Map OLD_ID_TO_KEY_MAP = new HashMap<>(); - static PaperweightDataConverters INSTANCE; - private static int DATA_VERSION; - - 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 final PaperweightAdapter adapter; - private final Map> converters = new EnumMap<>(LegacyType.class); - private final Map> inspectors = new EnumMap<>(LegacyType.class); - // Set on build - private DataFixer fixer; - - PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { - super(dataVersion); - DATA_VERSION = dataVersion; - INSTANCE = this; - this.adapter = adapter; - registerConverters(); - registerInspectors(); - } - - 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 static String fixName(String key, int srcVer, TypeReference type) { - return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, net.minecraft.nbt.StringTag.valueOf(key)), srcVer, DATA_VERSION) - .getValue().getAsString(); - } - - 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.contains("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(); - } - - 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, - 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.contains(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.contains(key, 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound.getList(key, 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - nbttaglist.set(j, convert(LegacyType.ITEM_INSTANCE, nbttaglist.getCompound(j), sourceVer, targetVer)); - } - } - - } - - //FAWE start - CBT > CT + //FAWE start - BinaryTag @SuppressWarnings("unchecked") @Override public T fixUp(FixType type, T original, int srcVer) { @@ -353,12 +123,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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( - References.BLOCK_STATE, - dynamic, - srcVer, - DATA_VERSION - ).getValue(); + net.minecraft.nbt.CompoundTag fixed = (net.minecraft.nbt.CompoundTag) INSTANCE.fixer.update(References.BLOCK_STATE, dynamic, srcVer, DATA_VERSION).getValue(); return nbtToState(fixed); } @@ -368,16 +133,31 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo if (tagCompound.contains("Properties", 10)) { sb.append('['); net.minecraft.nbt.CompoundTag props = tagCompound.getCompound("Properties"); - sb.append(props - .getAllKeys() - .stream() - .map(k -> k + "=" + props.getString(k).replace("\"", "")) - .collect(Collectors.joining(","))); + sb.append(props.getAllKeys().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, References.BIOME); } @@ -386,12 +166,158 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return fixName(key, srcVer, References.ITEM_NAME); } + private static String fixName(String key, int srcVer, TypeReference type) { + return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, net.minecraft.nbt.StringTag.valueOf(key)), srcVer, DATA_VERSION) + .getValue().getAsString(); + } + + private final PaperweightAdapter adapter; + + private static final NbtOps OPS_NBT = NbtOps.INSTANCE; + private static final int LEGACY_VERSION = 1343; + private static int DATA_VERSION; + public static PaperweightDataConverters 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(References.LEVEL), + PLAYER(References.PLAYER), + CHUNK(References.CHUNK), + BLOCK_ENTITY(References.BLOCK_ENTITY), + ENTITY(References.ENTITY), + ITEM_INSTANCE(References.ITEM_STACK), + OPTIONS(References.OPTIONS), + STRUCTURE(References.STRUCTURE); + + private final TypeReference type; + + LegacyType(TypeReference type) { + this.type = type; + DFU_TO_LEGACY.put(type.typeName(), this); + } + + public TypeReference getDFUType() { + return type; + } + } + + public PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { + super(dataVersion); + DATA_VERSION = dataVersion; + INSTANCE = this; + this.adapter = adapter; + registerConverters(); + registerInspectors(); + } + + // Called after fixers are built and ready for FIXING @Override - public DataFixer build(final Executor executor) { + public DataFixer buildUnoptimized() { return this.fixer = new WrappedDataFixer(DataFixers.getDataFixer()); } + @Override + public DataFixer buildOptimized(final Set requiredTypes, Executor executor) { + return buildUnoptimized(); + } + + @SuppressWarnings("unchecked") + 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 = PaperweightDataConverters.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 = PaperweightDataConverters.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.contains("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); } @@ -544,39 +470,146 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo registerEntityItemList(type, "ArmorItems", "HandItems"); } - public enum LegacyType { - LEVEL(References.LEVEL), - PLAYER(References.PLAYER), - CHUNK(References.CHUNK), - BLOCK_ENTITY(References.BLOCK_ENTITY), - ENTITY(References.ENTITY), - ITEM_INSTANCE(References.ITEM_STACK), - OPTIONS(References.OPTIONS), - STRUCTURE(References.STRUCTURE); + private static final Map OLD_ID_TO_KEY_MAP = new HashMap<>(); - private final TypeReference type; + 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")); + } - LegacyType(TypeReference type) { - this.type = type; - DFU_TO_LEGACY.put(type.typeName(), this); + 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; + } - public TypeReference getDFUType() { - return type; + 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.contains(key, 10)) { + convertCompound(LegacyType.ITEM_INSTANCE, nbttagcompound, key, sourceVer, targetVer); } } - public interface DataInspector { + private static void convertItems(net.minecraft.nbt.CompoundTag nbttagcompound, String key, int sourceVer, int targetVer) { + if (nbttagcompound.contains(key, 9)) { + net.minecraft.nbt.ListTag nbttaglist = nbttagcompound.getList(key, 10); - 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); + for (int j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set(j, convert(LegacyType.ITEM_INSTANCE, nbttaglist.getCompound(j), sourceVer, targetVer)); + } + } } @@ -635,7 +668,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataInspectorBlockEntity implements DataInspector { @@ -643,6 +675,50 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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); + } + } + + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (!cmp.contains("tag", 10)) { + return cmp; + } else { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("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.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; @@ -734,56 +810,10 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo map.put("minecraft:end_gateway", "minecraft:end_gateway"); map.put("minecraft:shield", "minecraft:shield"); } - - 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); - } - } - - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (!cmp.contains("tag", 10)) { - return cmp; - } else { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("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.contains("id"); - nbttagcompound2.putString("id", s1); - } - - convert(LegacyType.BLOCK_ENTITY, nbttagcompound2, sourceVer, targetVer); - if (flag) { - nbttagcompound2.remove("id"); - } - } - - return cmp; - } - } } private static class DataInspectorEntity implements DataInspector { - private static final Logger a = LogManager.getLogger(PaperweightDataConverters.class); - DataInspectorEntity() { } @@ -818,9 +848,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } + private abstract static class DataInspectorTagged implements DataInspector { private final ResourceLocation key; @@ -837,12 +867,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - abstract net.minecraft.nbt.CompoundTag inspectChecked( - net.minecraft.nbt.CompoundTag nbttagcompound, - int sourceVer, - int targetVer - ); - + abstract net.minecraft.nbt.CompoundTag inspectChecked(net.minecraft.nbt.CompoundTag nbttagcompound, int sourceVer, int targetVer); } private static class DataInspectorItemList extends DataInspectorTagged { @@ -861,7 +886,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return nbttagcompound; } - } private static class DataInspectorItem extends DataInspectorTagged { @@ -880,13 +904,31 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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.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"; @@ -1244,25 +1286,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo materials[453] = "minecraft:knowledge_book"; // Paper end } - - DataConverterMaterialId() { - } - - public int getDataVersion() { - return 102; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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; - } } private static class DataConverterArmorStand implements DataConverter { @@ -1281,7 +1304,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterBanner implements DataConverter { @@ -1328,13 +1350,42 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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.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"; @@ -1465,26 +1516,32 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo DataConverterPotionId.potions[126] = "minecraft:long_invisibility"; DataConverterPotionId.potions[127] = null; } + } - DataConverterPotionId() { + private static class DataConverterSpawnEgg implements DataConverter { + + private static final String[] eggs = new String[256]; + + DataConverterSpawnEgg() { } public int getDataVersion() { - return 102; + return 105; } public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:potion".equals(cmp.getString("id"))) { + 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 (!nbttagcompound1.contains("Potion", 8)) { - String s = DataConverterPotionId.potions[short0 & 127]; + if (!nbttagcompound2.contains("id", 8)) { + String s = DataConverterSpawnEgg.eggs[short0 & 255]; - nbttagcompound1.putString("Potion", s == null ? "minecraft:water" : s); - cmp.put("tag", nbttagcompound1); - if ((short0 & 16384) == 16384) { - cmp.putString("id", "minecraft:splash_potion"); + if (s != null) { + nbttagcompound2.putString("id", s); + nbttagcompound1.put("EntityTag", nbttagcompound2); + cmp.put("tag", nbttagcompound1); } } @@ -1495,11 +1552,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } - - private static class DataConverterSpawnEgg implements DataConverter { - - private static final String[] eggs = new String[256]; static { @@ -1571,50 +1623,11 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo DataConverterSpawnEgg.eggs[120] = "Villager"; DataConverterSpawnEgg.eggs[200] = "EnderCrystal"; } - - 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.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; - } } private static class DataConverterMinecart implements DataConverter { - private static final List a = Lists.newArrayList( - "MinecartRideable", - "MinecartChest", - "MinecartFurnace", - "MinecartTNT", - "MinecartSpawner", - "MinecartHopper", - "MinecartCommandBlock" - ); + private static final List a = Lists.newArrayList("MinecartRideable", "MinecartChest", "MinecartFurnace", "MinecartTNT", "MinecartSpawner", "MinecartHopper", "MinecartCommandBlock"); DataConverterMinecart() { } @@ -1638,7 +1651,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterMobSpawner implements DataConverter { @@ -1683,7 +1695,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } } - } private static class DataConverterUUID implements DataConverter { @@ -1702,47 +1713,11 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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" - ); + 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() { } @@ -1771,7 +1746,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterSaddle implements DataConverter { @@ -1796,7 +1770,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterHanging implements DataConverter { @@ -1835,7 +1808,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterDropChances implements DataConverter { @@ -1859,15 +1831,13 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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) { + 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 { @@ -1903,7 +1873,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo nbttagcompound.remove("Riding"); return nbttagcompound1; } - } private static class DataConverterBook implements DataConverter { @@ -1928,39 +1897,42 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo if (!"null".equals(s) && !StringUtil.isNullOrEmpty(s)) { if ((s.charAt(0) != 34 || s.charAt(s.length() - 1) != 34) && (s.charAt(0) != 123 || s.charAt(s.length() - 1) != 125)) { - object = new TextComponent(s); + object = Component.literal(s); } else { try { object = GsonHelper.fromJson(DataConverterSignText.a, s, Component.class, true); if (object == null) { - object = new TextComponent(""); + object = Component.literal(""); } - } catch (JsonParseException ignored) { + } catch (JsonParseException jsonparseexception) { + ; } if (object == null) { try { - object = Component.Serializer.fromJson(s); - } catch (JsonParseException ignored) { + object = Component.Serializer.fromJson(s, MinecraftServer.getServer().registryAccess()); + } catch (JsonParseException jsonparseexception1) { + ; } } if (object == null) { try { - object = Component.Serializer.fromJsonLenient(s); - } catch (JsonParseException ignored) { + object = Component.Serializer.fromJsonLenient(s, MinecraftServer.getServer().registryAccess()); + } catch (JsonParseException jsonparseexception2) { + ; } } if (object == null) { - object = new TextComponent(s); + object = Component.literal(s); } } } else { - object = new TextComponent(""); + object = Component.literal(""); } - nbttaglist.set(i, net.minecraft.nbt.StringTag.valueOf(Component.Serializer.toJson(object))); + nbttaglist.set(i, StringTag.valueOf(Component.Serializer.toJson(object, MinecraftServer.getServer().registryAccess()))); } nbttagcompound1.put("pages", nbttaglist); @@ -1969,7 +1941,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterCookedFish implements DataConverter { @@ -1990,7 +1961,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterZombie implements DataConverter { @@ -2012,7 +1982,8 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo if (cmp.contains("VillagerProfession", 99)) { try { i = this.convert(cmp.getInt("VillagerProfession")); - } catch (RuntimeException ignored) { + } catch (RuntimeException runtimeexception) { + ; } } @@ -2032,7 +2003,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo private int convert(int i) { return i >= 0 && i < 6 ? i : -1; } - } private static class DataConverterVBO implements DataConverter { @@ -2048,7 +2018,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo cmp.putString("useVbo", "true"); return cmp; } - } private static class DataConverterGuardian implements DataConverter { @@ -2071,7 +2040,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterSkeleton implements DataConverter { @@ -2100,7 +2068,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterZombieType implements DataConverter { @@ -2139,7 +2106,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterHorse implements DataConverter { @@ -2182,13 +2148,29 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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"); @@ -2214,8 +2196,13 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo DataConverterTileEntity.a.put("Structure", "minecraft:structure_block"); DataConverterTileEntity.a.put("Trap", "minecraft:dispenser"); } + } - DataConverterTileEntity() { + private static class DataConverterEntity implements DataConverter { + + private static final Map a = Maps.newHashMap(); + + DataConverterEntity() { } public int getDataVersion() { @@ -2223,7 +2210,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo } public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - String s = DataConverterTileEntity.a.get(cmp.getString("id")); + String s = DataConverterEntity.a.get(cmp.getString("id")); if (s != null) { cmp.putString("id", s); @@ -2231,11 +2218,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } - - private static class DataConverterEntity implements DataConverter { - - private static final Map a = Maps.newHashMap(); static { DataConverterEntity.a.put("AreaEffectCloud", "minecraft:area_effect_cloud"); @@ -2314,23 +2296,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo DataConverterEntity.a.put("ZombieHorse", "minecraft:zombie_horse"); DataConverterEntity.a.put("ZombieVillager", "minecraft:zombie_villager"); } - - 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; - } } private static class DataConverterPotionWater implements DataConverter { @@ -2345,8 +2310,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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)) { + 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.contains("Potion", 8)) { @@ -2360,7 +2324,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterShulker implements DataConverter { @@ -2379,12 +2342,11 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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"}; + 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() { } @@ -2421,7 +2383,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterShulkerBoxBlock implements DataConverter { @@ -2440,7 +2401,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterLang implements DataConverter { @@ -2459,7 +2419,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterTotem implements DataConverter { @@ -2478,7 +2437,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterBedBlock implements DataConverter { @@ -2526,7 +2484,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterBedItem implements DataConverter { @@ -2545,26 +2502,22 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterSignText implements DataConverter { public static final Gson a = new GsonBuilder().registerTypeAdapter(Component.class, new JsonDeserializer() { - MutableComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws - JsonParseException { + MutableComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { if (jsonelement.isJsonPrimitive()) { - return new TextComponent(jsonelement.getAsString()); + return Component.literal(jsonelement.getAsString()); } else if (jsonelement.isJsonArray()) { JsonArray jsonarray = jsonelement.getAsJsonArray(); MutableComponent ichatbasecomponent = null; + Iterator iterator = jsonarray.iterator(); - for (final JsonElement jsonelement1 : jsonarray) { - MutableComponent ichatbasecomponent1 = this.a( - jsonelement1, - jsonelement1.getClass(), - jsondeserializationcontext - ); + while (iterator.hasNext()) { + JsonElement jsonelement1 = (JsonElement) iterator.next(); + MutableComponent ichatbasecomponent1 = this.a(jsonelement1, jsonelement1.getClass(), jsondeserializationcontext); if (ichatbasecomponent == null) { ichatbasecomponent = ichatbasecomponent1; @@ -2579,11 +2532,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo } } - public Object deserialize( - JsonElement jsonelement, - Type type, - JsonDeserializationContext jsondeserializationcontext - ) throws JsonParseException { + public Object deserialize(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { return this.a(jsonelement, type, jsondeserializationcontext); } }).create(); @@ -2612,45 +2561,46 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo if (!"null".equals(s1) && !StringUtil.isNullOrEmpty(s1)) { if ((s1.charAt(0) != 34 || s1.charAt(s1.length() - 1) != 34) && (s1.charAt(0) != 123 || s1.charAt(s1.length() - 1) != 125)) { - object = new TextComponent(s1); + object = Component.literal(s1); } else { try { object = GsonHelper.fromJson(DataConverterSignText.a, s1, Component.class, true); if (object == null) { - object = new TextComponent(""); + object = Component.literal(""); } - } catch (JsonParseException ignored) { + } catch (JsonParseException jsonparseexception) { + ; } if (object == null) { try { - object = Component.Serializer.fromJson(s1); - } catch (JsonParseException ignored) { + object = Component.Serializer.fromJson(s1, MinecraftServer.getServer().registryAccess()); + } catch (JsonParseException jsonparseexception1) { + ; } } if (object == null) { try { - object = Component.Serializer.fromJsonLenient(s1); - } catch (JsonParseException ignored) { + object = Component.Serializer.fromJsonLenient(s1, MinecraftServer.getServer().registryAccess()); + } catch (JsonParseException jsonparseexception2) { + ; } } if (object == null) { - object = new TextComponent(s1); + object = Component.literal(s1); } } } else { - object = new TextComponent(""); + object = Component.literal(""); } - nbttagcompound.putString(s, Component.Serializer.toJson(object)); + nbttagcompound.putString(s, Component.Serializer.toJson(object, MinecraftServer.getServer().registryAccess())); } - } private static class DataInspectorPlayerVehicle implements DataInspector { - @Override public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { if (cmp.contains("RootVehicle", 10)) { @@ -2663,11 +2613,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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.contains("Player", 10)) { @@ -2676,11 +2624,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataInspectorStructure implements DataInspector { - @Override public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { net.minecraft.nbt.ListTag nbttaglist; @@ -2711,11 +2657,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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.contains("Level", 10)) { @@ -2727,14 +2671,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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 - ) - ); + nbttaglist.set(j, convert(LegacyType.ENTITY, (net.minecraft.nbt.CompoundTag) nbttaglist.get(j), sourceVer, targetVer)); } } @@ -2742,25 +2679,16 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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 - ) - ); + 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.contains("Passengers", 9)) { @@ -2773,11 +2701,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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); @@ -2792,11 +2718,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataInspectorVillagers implements DataInspector { - ResourceLocation entityVillager = getKey("EntityVillager"); @Override @@ -2820,11 +2744,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataInspectorMobSpawnerMinecart implements DataInspector { - ResourceLocation entityMinecartMobSpawner = getKey("EntityMinecartMobSpawner"); ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner"); @@ -2839,11 +2761,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataInspectorMobSpawnerMobs implements DataInspector { - ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner"); @Override @@ -2864,11 +2784,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataInspectorCommandBlock implements DataInspector { - ResourceLocation tileEntityCommand = getKey("TileEntityCommand"); @Override @@ -2881,63 +2799,5 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } - - @SuppressWarnings("unchecked") - 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 = PaperweightDataConverters.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 = PaperweightDataConverters.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); - } - - } - } diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2/PaperweightFakePlayer.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightFakePlayer.java similarity index 78% rename from worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2/PaperweightFakePlayer.java rename to worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightFakePlayer.java index e5ff26672..792942843 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2/PaperweightFakePlayer.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightFakePlayer.java @@ -17,18 +17,19 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R2; +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R4; import com.mojang.authlib.GameProfile; -import net.minecraft.network.chat.ChatType; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ServerboundClientInformationPacket; +import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.stats.Stat; import net.minecraft.world.MenuProvider; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.player.ChatVisiblity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.phys.Vec3; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; @@ -37,15 +38,14 @@ import java.util.OptionalInt; import java.util.UUID; class PaperweightFakePlayer extends ServerPlayer { - - private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile( - UUID.nameUUIDFromBytes("worldedit".getBytes()), - "[WorldEdit]" - ); + private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]"); private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D); + private static final ClientInformation FAKE_CLIENT_INFO = new ClientInformation( + "en_US", 16, ChatVisiblity.FULL, true, 0, HumanoidArm.LEFT, false, false + ); PaperweightFakePlayer(ServerLevel world) { - super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE); + super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE, FAKE_CLIENT_INFO); } @Override @@ -72,17 +72,13 @@ class PaperweightFakePlayer extends ServerPlayer { } @Override - public void updateOptions(ServerboundClientInformationPacket packet) { + public void updateOptions(ClientInformation clientOptions) { } @Override public void displayClientMessage(Component message, boolean actionBar) { } - @Override - public void sendMessage(Component message, ChatType type, UUID sender) { - } - @Override public void awardStat(Stat stat, int amount) { } @@ -97,7 +93,6 @@ class PaperweightFakePlayer extends ServerPlayer { } @Override - public void openTextEdit(SignBlockEntity sign) { + public void openTextEdit(SignBlockEntity sign, boolean front) { } - } diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightWorldNativeAccess.java similarity index 74% rename from worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2/PaperweightWorldNativeAccess.java rename to worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightWorldNativeAccess.java index e9656539a..f7e5cee3f 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R2/PaperweightWorldNativeAccess.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightWorldNativeAccess.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R2; +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R4; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.internal.block.BlockStateIdAccess; @@ -27,21 +27,19 @@ import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.block.BlockState; import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.FullChunkStatus; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.chunk.LevelChunk; -import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.event.block.BlockPhysicsEvent; import java.lang.ref.WeakReference; import java.util.Objects; import javax.annotation.Nullable; -public class PaperweightWorldNativeAccess implements - WorldNativeAccess { - +public class PaperweightWorldNativeAccess implements WorldNativeAccess { private static final int UPDATE = 1; private static final int NOTIFY = 2; @@ -83,19 +81,12 @@ public class PaperweightWorldNativeAccess implements @Nullable @Override - public net.minecraft.world.level.block.state.BlockState setBlockState( - LevelChunk chunk, - BlockPos position, - net.minecraft.world.level.block.state.BlockState state - ) { + public net.minecraft.world.level.block.state.BlockState setBlockState(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState state) { return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE)); } @Override - public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition( - net.minecraft.world.level.block.state.BlockState block, - BlockPos position - ) { + public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(net.minecraft.world.level.block.state.BlockState block, BlockPos position) { return Block.updateFromNeighbourShapes(block, getWorld(), position); } @@ -115,12 +106,7 @@ public class PaperweightWorldNativeAccess implements } @Override - public void notifyBlockUpdate( - LevelChunk chunk, - BlockPos position, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { + public void notifyBlockUpdate(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY); } @@ -128,7 +114,7 @@ public class PaperweightWorldNativeAccess implements @Override public boolean isChunkTicking(LevelChunk chunk) { - return chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); + return chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING); } @Override @@ -139,11 +125,7 @@ public class PaperweightWorldNativeAccess implements } @Override - public void notifyNeighbors( - BlockPos pos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { + public void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { ServerLevel world = getWorld(); if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { world.updateNeighborsAt(pos, oldState.getBlock()); @@ -162,27 +144,20 @@ public class PaperweightWorldNativeAccess implements } } + // Not sure why neighborChanged is deprecated private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { - world.getBlockState(neighborPos).neighborChanged(world, neighborPos, block, pos, false); + world.getBlockState(neighborPos).handleNeighborChanged(world, neighborPos, block, pos, false); } @Override - public void updateNeighbors( - BlockPos pos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState, - int recursionLimit - ) { + public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) { ServerLevel world = getWorld(); // a == updateNeighbors // b == updateDiagonalNeighbors oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { CraftWorld craftWorld = world.getWorld(); - BlockPhysicsEvent event = new BlockPhysicsEvent( - craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), - CraftBlockData.fromData(newState) - ); + BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState)); world.getCraftServer().getPluginManager().callEvent(event); if (event.isCancelled()) { return; @@ -193,19 +168,13 @@ public class PaperweightWorldNativeAccess implements } @Override - public void onBlockStateChange( - BlockPos pos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { + public void onBlockStateChange(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { getWorld().onBlockStateChange(pos, oldState, newState); } - //FAWE start @Override public void flush() { } - //FAWE end } diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightBlockMaterial.java similarity index 69% rename from worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightBlockMaterial.java rename to worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightBlockMaterial.java index b5da62e0f..9c2292451 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightBlockMaterial.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightBlockMaterial.java @@ -1,28 +1,24 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4; import com.google.common.base.Suppliers; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.util.ReflectionUtil; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.world.registry.BlockMaterial; import net.minecraft.core.BlockPos; +import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.world.level.EmptyBlockGetter; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.Material; +import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.material.PushReaction; -import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData; +import org.bukkit.craftbukkit.block.data.CraftBlockData; public class PaperweightBlockMaterial implements BlockMaterial { private final Block block; private final BlockState blockState; - private final Material material; - private final boolean isTranslucent; private final CraftBlockData craftBlockData; private final org.bukkit.Material craftMaterial; private final int opacity; @@ -35,22 +31,16 @@ public class PaperweightBlockMaterial implements BlockMaterial { public PaperweightBlockMaterial(Block block, BlockState blockState) { this.block = block; this.blockState = blockState; - this.material = blockState.getMaterial(); this.craftBlockData = CraftBlockData.fromData(blockState); this.craftMaterial = craftBlockData.getMaterial(); - BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, Refraction.pickName( - "properties", "aO")); - this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo, - Refraction.pickName("canOcclude", "n") - ); opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity( BlockPos.ZERO, blockState ); - tile = tileEntity == null - ? null - : new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); + tile = tileEntity == null ? null : new PaperweightLazyCompoundTag( + Suppliers.memoize(() -> tileEntity.saveWithId(DedicatedServer.getServer().registryAccess())) + ); } public Block getBlock() { @@ -65,10 +55,6 @@ public class PaperweightBlockMaterial implements BlockMaterial { return craftBlockData; } - public Material getMaterial() { - return material; - } - @Override public boolean isAir() { return blockState.isAir(); @@ -81,7 +67,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isOpaque() { - return material.isSolidBlocking(); + return blockState.canOcclude(); } @Override @@ -91,12 +77,13 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isLiquid() { - return material.isLiquid(); + return !blockState.getFluidState().is(Fluids.EMPTY); } @Override public boolean isSolid() { - return material.isSolid(); + // No access to world -> EmptyBlockGetter + return blockState.isSolidRender(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); } @Override @@ -126,27 +113,27 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isFragileWhenPushed() { - return material.getPushReaction() == PushReaction.DESTROY; + return blockState.getPistonPushReaction() == PushReaction.DESTROY; } @Override public boolean isUnpushable() { - return material.getPushReaction() == PushReaction.BLOCK; + return blockState.getPistonPushReaction() == PushReaction.BLOCK; } @Override public boolean isTicksRandomly() { - return block.isRandomlyTicking(blockState); + return blockState.isRandomlyTicking(); } @Override public boolean isMovementBlocker() { - return material.isSolid(); + return craftMaterial.isSolid(); } @Override public boolean isBurnable() { - return material.isFlammable(); + return craftMaterial.isBurnable(); } @Override @@ -157,12 +144,12 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isReplacedDuringPlacement() { - return material.isReplaceable(); + return blockState.canBeReplaced(); } @Override public boolean isTranslucent() { - return isTranslucent; + return !blockState.canOcclude(); } @Override @@ -183,7 +170,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public int getMapColor() { // rgb field - return material.getColor().col; + return block.defaultMapColor().col; } } diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java similarity index 82% rename from worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightFaweAdapter.java rename to worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java index 8b96e2ea6..b263c9ced 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4; import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; @@ -12,14 +12,13 @@ import com.fastasyncworldedit.core.util.NbtUtils; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.mojang.serialization.Codec; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.blocks.TileEntityBlock; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R2.PaperweightAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.regen.PaperweightRegen; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.regen.PaperweightRegen; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.internal.block.BlockStateIdAccess; @@ -35,6 +34,7 @@ import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.nbt.BinaryTag; import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; @@ -45,7 +45,6 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; -import 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.item.ItemType; @@ -53,44 +52,48 @@ import com.sk89q.worldedit.world.registry.BlockMaterial; import io.papermc.lib.PaperLib; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; import net.minecraft.core.WritableRegistry; -import net.minecraft.nbt.IntTag; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.StringRepresentable; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.DirectionProperty; import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.NamespacedKey; import org.bukkit.World; import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_18_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_18_R2.CraftServer; -import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_18_R2.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.entity.Player; import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -104,11 +107,24 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; +import static net.minecraft.core.registries.Registries.BIOME; + public final class PaperweightFaweAdapter extends FaweAdapter { private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; + private static final Codec COMPONENTS_CODEC = DataComponentPatch.CODEC.optionalFieldOf( + "components", DataComponentPatch.EMPTY + ).codec(); - private final PaperweightAdapter parent; + static { + try { + CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE = ChunkHolder.class.getDeclaredMethod("wasAccessibleSinceLastSave"); + } catch (NoSuchMethodException ignored) { // may not be present in newer paper versions + } + } + + private final com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R4.PaperweightAdapter parent; // ------------------------------------------------------------------------ // Code that may break between versions of Minecraft // ------------------------------------------------------------------------ @@ -119,7 +135,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter>> allBlockProperties = null; public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { - this.parent = new PaperweightAdapter(); + this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R4.PaperweightAdapter(); } @Nullable @@ -128,6 +144,10 @@ public final class PaperweightFaweAdapter extends FaweAdapter getParent() { return parent; @@ -219,7 +239,8 @@ public final class PaperweightFaweAdapter extends FaweAdapter> 4; - LevelChunkSection section = levelChunkSections[y4]; - - net.minecraft.world.level.block.state.BlockState existing; - if (section == null) { - existing = ((PaperweightBlockMaterial) BlockTypes.AIR.getDefaultState().getMaterial()).getState(); - } else { - existing = section.getBlockState(x & 15, y & 15, z & 15); - } - - levelChunk.removeBlockEntity(blockPos); // Force delete the old tile entity - - CompoundBinaryTag compoundTag = state instanceof BaseBlock ? state.getNbt() : null; - if (compoundTag != null || existing instanceof TileEntityBlock) { - level.setBlock(blockPos, blockState, 0); - // remove tile - if (compoundTag != null) { - // We will assume that the tile entity was created for us, - // though we do not do this on the Forge version - BlockEntity blockEntity = level.getBlockEntity(blockPos); - if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(compoundTag); - tag.put("x", IntTag.valueOf(x)); - tag.put("y", IntTag.valueOf(y)); - tag.put("z", IntTag.valueOf(z)); - blockEntity.load(tag); // readTagIntoTileEntity - load data - } - } - } else { - if (existing == blockState) { - return true; - } - levelChunk.setBlockState(blockPos, blockState, false); - } - if (update) { - level.getMinecraftWorld().sendBlockUpdated(blockPos, existing, blockState, 0); - } - return true; - } - @Override public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); @@ -343,7 +316,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(mcEntity, minecraftTag); + readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); @@ -474,7 +447,8 @@ public final class PaperweightFaweAdapter extends FaweAdapter stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag) */ Stream.empty(); @@ -516,11 +490,18 @@ public final class PaperweightFaweAdapter extends FaweAdapter getEntities(org.bukkit.World world) { - // Quickly add each entity to a list copy. - List mcEntities = new ArrayList<>(); - getServerLevel(world).entityManager.getEntityGetter().getAll().forEach(mcEntities::add); - - List list = new ArrayList<>(); - mcEntities.forEach((mcEnt) -> { - org.bukkit.entity.Entity bukkitEntity = mcEnt.getBukkitEntity(); - if (bukkitEntity.isValid()) { - list.add(bukkitEntity); - } - - }); - return list; - } - @Override public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { + final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess(); final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); - final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); - weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); - return weStack; + final net.minecraft.nbt.Tag tag = COMPONENTS_CODEC.encodeStart( + registryAccess.createSerializationContext(NbtOps.INSTANCE), + nmsStack.getComponentsPatch() + ).getOrThrow(); + return new BaseItemStack( + BukkitAdapter.asItemType(itemStack.getType()), + LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag)), + itemStack.getAmount() + ); } @Override @@ -577,17 +548,12 @@ public final class PaperweightFaweAdapter extends FaweAdapter registry = MinecraftServer .getServer() .registryAccess() - .ownedRegistryOrThrow(Registry.BIOME_REGISTRY); + .registryOrThrow(BIOME); ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.getId()); Biome biome = registry.get(resourceLocation); return registry.getId(biome); @@ -616,8 +582,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter biomeRegistry = (WritableRegistry) ((CraftServer) Bukkit.getServer()) .getServer() .registryAccess() - .ownedRegistryOrThrow( - Registry.BIOME_REGISTRY); + .registryOrThrow(BIOME); List keys = biomeRegistry.stream() .map(biomeRegistry::getKey).filter(Objects::nonNull).toList(); List namespacedKeys = new ArrayList<>(); @@ -659,4 +624,16 @@ public final class PaperweightFaweAdapter extends FaweAdapter currentTick; if (nextTick || cachedChanges.size() >= 1024) { if (nextTick) { @@ -140,7 +141,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); - private static final Function nmsTile2We = - tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); + private static final Function nmsTile2We = tileEntity -> new PaperweightLazyCompoundTag( + Suppliers.memoize(() -> tileEntity.saveWithId(DedicatedServer.getServer().registryAccess())) + ); private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin .getInstance() .getBukkitImplAdapter()); @@ -130,7 +114,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc this.maxSectionPosition = maxHeight >> 4; this.skyLight = new DataLayer[getSectionCount()]; this.blockLight = new DataLayer[getSectionCount()]; - this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); + this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME); this.biomeHolderIdMap = biomeRegistry.asHolderIdMap(); } @@ -260,7 +244,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (blockEntity == null) { return null; } - return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)); + return new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()))); } @Override @@ -289,8 +273,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( LightLayer.BLOCK, sectionPos, - dataLayer, - true + dataLayer ); } skyLight[alayer] = dataLayer; @@ -317,7 +300,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc Arrays.fill(LAYER_COUNT, (byte) 15); dataLayer = new DataLayer(LAYER_COUNT); ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos, - dataLayer, true + dataLayer ); } blockLight[alayer] = dataLayer; @@ -334,7 +317,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public CompoundTag getEntity(UUID uuid) { - Entity entity = serverLevel.getEntity(uuid); + ensureLoaded(serverLevel, chunkX, chunkZ); + List entities = PaperweightPlatformAdapter.getEntities(getChunk()); + Entity entity = null; + for (Entity e : entities) { + if (e.getUUID().equals(uuid)) { + entity = e; + break; + } + } if (entity != null) { org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); @@ -349,6 +340,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public Set getEntities() { + ensureLoaded(serverLevel, chunkX, chunkZ); List entities = PaperweightPlatformAdapter.getEntities(getChunk()); if (entities.isEmpty()) { return Collections.emptySet(); @@ -385,7 +377,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc public Iterator iterator() { Iterable result = entities.stream().map(input -> { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(input, tag); + input.save(tag); return (CompoundTag) adapter.toNative(tag); }).collect(Collectors.toList()); return result.iterator(); @@ -474,7 +466,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc synchronized (super.sectionLocks[getSectionIndex]) { LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; if (createCopy && existingSection != null) { - copy.storeBiomes(getSectionIndex, existingSection.getBiomes().copy()); + copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); } if (existingSection == null) { @@ -507,8 +499,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } } } else { - PalettedContainer> biomeData = existingSection.getBiomes(); - setBiomesToPalettedContainer(biomes[setSectionIndex], biomeData); + setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); } } } @@ -543,7 +534,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc System.arraycopy(tmpLoad, 0, copyArr, 0, 4096); copy.storeSection(getSectionIndex, copyArr); if (biomes != null && existingSection != null) { - copy.storeBiomes(getSectionIndex, existingSection.getBiomes().copy()); + copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); } } @@ -555,8 +546,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc .getBukkitImplAdapter() .getInternalBiomeId( BiomeTypes.PLAINS)), - PalettedContainer.Strategy.SECTION_BIOMES, - null + PalettedContainer.Strategy.SECTION_BIOMES ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); newSection = PaperweightPlatformAdapter.newChunkSection( layerNo, @@ -616,11 +606,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc sectionLock.writeLock().unlock(); } - PalettedContainer> biomeData = existingSection.getBiomes(); - - if (biomes != null && biomes[setSectionIndex] != null) { - setBiomesToPalettedContainer(biomes[setSectionIndex], biomeData); - } + PalettedContainer> biomeData = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); newSection = PaperweightPlatformAdapter.newChunkSection( @@ -705,7 +695,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { for (UUID uuid : entityRemoves) { - Entity entity = nmsWorld.entityManager.getEntityGetter().get(uuid); + Entity entity = nmsWorld.getEntities().get(uuid); if (entity != null) { removeEntity(entity); } @@ -800,7 +790,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc tag.put("x", IntTag.valueOf(x)); tag.put("y", IntTag.valueOf(y)); tag.put("z", IntTag.valueOf(z)); - tileEntity.load(tag); + tileEntity.loadWithComponents(tag, DedicatedServer.getServer().registryAccess()); } } } @@ -1076,8 +1066,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( lightLayer, sectionPos, - dataLayer, - true + dataLayer ); } synchronized (dataLayer) { @@ -1095,22 +1084,35 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } } - private void setBiomesToPalettedContainer( - final BiomeType[] biomes, - PalettedContainer> data + private PalettedContainer> setBiomesToPalettedContainer( + final BiomeType[][] biomes, + final int sectionIndex, + final PalettedContainerRO> data ) { - int index = 0; - if (biomes == null) { - return; + PalettedContainer> biomeData; + if (data instanceof PalettedContainer> palettedContainer) { + biomeData = palettedContainer; + } else { + LOGGER.warn( + "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + + "type {} but got {}", + PalettedContainer.class.getSimpleName(), + data.getClass().getSimpleName() + ); + biomeData = data.recreate(); } - for (int y = 0; y < 4; y++) { + BiomeType[] sectionBiomes; + if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { + return biomeData; + } + for (int y = 0, index = 0; y < 4; y++) { for (int z = 0; z < 4; z++) { for (int x = 0; x < 4; x++, index++) { - BiomeType biomeType = biomes[index]; + BiomeType biomeType = sectionBiomes[index]; if (biomeType == null) { continue; } - data.set( + biomeData.set( x, y, z, @@ -1122,6 +1124,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } } } + return biomeData; } @Override diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks_Copy.java similarity index 86% rename from worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks_Copy.java rename to worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks_Copy.java index b007ea3b4..c0a7bda52 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks_Copy.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.queue.IBlocks; @@ -8,19 +8,23 @@ import com.google.common.base.Suppliers; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; 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.BlockTypesCache; import net.minecraft.core.Holder; +import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; import java.util.Arrays; @@ -33,6 +37,8 @@ import java.util.concurrent.Future; public class PaperweightGetBlocks_Copy implements IChunkGet { + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private final Map tiles = new HashMap<>(); private final Set entities = new HashSet<>(); private final char[][] blocks; @@ -57,7 +63,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { blockEntity.getBlockPos().getY(), blockEntity.getBlockPos().getZ() ), - new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)) + new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()))) ); } @@ -76,7 +82,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { protected void storeEntity(Entity entity) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(entity, compoundTag); + entity.save(compoundTag); entities.add((CompoundTag) adapter.toNative(compoundTag)); } @@ -166,11 +172,19 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { blocks[layer] = data; } - protected void storeBiomes(int layer, PalettedContainer> biomeData) { + protected void storeBiomes(int layer, PalettedContainerRO> biomeData) { if (biomes == null) { biomes = new PalettedContainer[getSectionCount()]; } - biomes[layer] = biomeData; + if (biomeData instanceof PalettedContainer> palettedContainer) { + biomes[layer] = palettedContainer.copy(); + } else { + LOGGER.error( + "Cannot correctly save biomes to history. Expected class type {} but got {}", + PalettedContainer.class.getSimpleName(), + biomeData.getClass().getSimpleName() + ); + } } @Override diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightMapChunkUtil.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightMapChunkUtil.java similarity index 88% rename from worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightMapChunkUtil.java rename to worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightMapChunkUtil.java index 9189ca251..9e226b088 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightMapChunkUtil.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightMapChunkUtil.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4; import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; import com.sk89q.worldedit.bukkit.adapter.Refraction; @@ -10,10 +10,10 @@ public class PaperweightMapChunkUtil extends MapChunkUtil serverLevel + io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel .getChunkSource() - .addRegionTicket(TicketType.PLUGIN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE)); + .addRegionTicket(TicketType.UNLOAD_COOLDOWN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE)); } public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) { @@ -286,20 +338,21 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return; } ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ); - // UNLOADED_CHUNK - Optional optional = ((Either) chunkHolder - .getTickingChunkFuture() - .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left(); + LevelChunk levelChunk; if (PaperLib.isPaper()) { // getChunkAtIfLoadedImmediately is paper only - optional = optional.or(() -> Optional.ofNullable(nmsWorld + levelChunk = nmsWorld .getChunkSource() - .getChunkAtIfLoadedImmediately(chunkX, chunkZ))); + .getChunkAtIfLoadedImmediately(chunkX, chunkZ); + } else { + levelChunk = ((Optional) ((Either) chunkHolder + .getTickingChunkFuture() // method is not present with new paper chunk system + .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left()) + .orElse(null); } - if (optional.isEmpty()) { + if (levelChunk == null) { return; } - LevelChunk levelChunk = optional.get(); TaskManager.taskManager().task(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { @@ -307,9 +360,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { levelChunk, nmsWorld.getChunkSource().getLightEngine(), null, - null, - true, - false // last false is to not bother with x-ray + null + // last false is to not bother with x-ray ); } else { // deprecated on paper - deprecation suppressed @@ -317,8 +369,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { levelChunk, nmsWorld.getChunkSource().getLightEngine(), null, - null, - true + null ); } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); @@ -424,12 +475,11 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { .getBukkitImplAdapter() .getInternalBiomeId( BiomeTypes.PLAINS)), - PalettedContainer.Strategy.SECTION_BIOMES, - null + PalettedContainer.Strategy.SECTION_BIOMES ); } - return new LevelChunkSection(layer, blockStatePalettedContainer, biomes); + return new LevelChunkSection(blockStatePalettedContainer, biomes); } catch (final Throwable e) { throw e; } finally { @@ -447,15 +497,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @Nullable PalettedContainer> biomes ) { if (biomes == null) { - return new LevelChunkSection(layer, biomeRegistry); + return new LevelChunkSection(biomeRegistry); } PalettedContainer dataPaletteBlocks = new PalettedContainer<>( Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), - PalettedContainer.Strategy.SECTION_STATES, - null + PalettedContainer.Strategy.SECTION_STATES ); - return new LevelChunkSection(layer, dataPaletteBlocks, biomes); + return new LevelChunkSection(dataPaletteBlocks, biomes); } /** @@ -492,8 +541,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { PalettedContainer> biomePalettedContainer = new PalettedContainer<>( biomeRegistry, biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), - PalettedContainer.Strategy.SECTION_BIOMES, - null + PalettedContainer.Strategy.SECTION_BIOMES ); final Palette> biomePalette; @@ -571,7 +619,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } public static BiomeType adapt(Holder biome, LevelAccessor levelAccessor) { - final Registry biomeRegistry = levelAccessor.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY); + final Registry biomeRegistry = levelAccessor.registryAccess().registryOrThrow(BIOME); if (biomeRegistry.getKey(biome.value()) == null) { return biomeRegistry.asHolderIdMap().getId(biome) == -1 ? BiomeTypes.OCEAN : null; @@ -581,13 +629,11 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { try { - // Do the method ourselves to avoid trying to reflect generic method parameters - // similar to removeGameEventListener if (levelChunk.loaded || levelChunk.level.isClientSide()) { BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos()); if (blockEntity != null) { if (!levelChunk.level.isClientSide) { - methodRemoveGameEventListener.invoke(levelChunk, beacon); + methodRemoveGameEventListener.invoke(levelChunk, beacon, levelChunk.level); } fieldRemove.set(beacon, true); } @@ -599,30 +645,32 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } static List getEntities(LevelChunk chunk) { - return chunk.level.entityManager.getEntities(chunk.getPos()); - } - - public static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { - boolean isVillager = entity instanceof AbstractVillager && !Fawe.isMainThread(); - boolean unset = false; - if (isVillager) { - try { - if (fieldOffers.get(entity) != null) { - fieldOffers.set(entity, OFFERS); - unset = true; + ExceptionCollector collector = new ExceptionCollector<>(); + if (PaperLib.isPaper()) { + if (POST_CHUNK_REWRITE) { + try { + //noinspection unchecked + return (List) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level.getEntityLookup().getChunk(chunk.locX, chunk.locZ)); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=true]", e); } - } catch (IllegalAccessException e) { - throw new RuntimeException("Failed to set offers field to villager to avoid async catcher.", e); } - } - entity.save(compoundTag); - if (unset) { try { - fieldOffers.set(entity, null); + EntityList entityList = (EntityList) LEVEL_CHUNK_ENTITIES.get(chunk); + return List.of(entityList.getRawData()); } catch (IllegalAccessException e) { - throw new RuntimeException("Failed to set offers field to null again on villager.", e); + collector.add(new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=false]", e)); + // fall through } } + try { + //noinspection unchecked + return ((PersistentEntitySectionManager) (SERVER_LEVEL_ENTITY_MANAGER.get(chunk.level))).getEntities(chunk.getPos()); + } catch (IllegalAccessException e) { + collector.add(new RuntimeException("Failed to lookup entities [PAPER=false]", e)); + } + collector.throwIfPresent(); + return List.of(); } record FakeIdMapBlock(int size) implements IdMap { diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightPostProcessor.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPostProcessor.java similarity index 99% rename from worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightPostProcessor.java rename to worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPostProcessor.java index abc8d6150..bc094a916 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightPostProcessor.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPostProcessor.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.ProcessorScope; diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighter.java similarity index 90% rename from worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighter.java rename to worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighter.java index c832fc98a..476978b57 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighter.java @@ -1,14 +1,14 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4; import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.queue.IQueueExtent; -import net.minecraft.server.MCUtil; +import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.TicketType; import net.minecraft.util.Unit; import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.status.ChunkStatus; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -18,7 +18,7 @@ import java.util.function.IntConsumer; public class PaperweightStarlightRelighter extends StarlightRelighter { private static final TicketType FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); - private static final int LIGHT_LEVEL = MCUtil.getTicketLevelFor(ChunkStatus.LIGHT); + private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkStatus.getDistance(ChunkStatus.LIGHT); public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { super(serverLevel, queue); diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighterFactory.java similarity index 88% rename from worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighterFactory.java rename to worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighterFactory.java index 735bcc677..1425088b8 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightStarlightRelighterFactory.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighterFactory.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4; import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; @@ -7,7 +7,7 @@ import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.sk89q.worldedit.world.World; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; +import org.bukkit.craftbukkit.CraftWorld; import javax.annotation.Nonnull; diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/nbt/PaperweightLazyCompoundTag.java similarity index 98% rename from worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/nbt/PaperweightLazyCompoundTag.java rename to worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/nbt/PaperweightLazyCompoundTag.java index a890d66a4..11d3c940a 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/nbt/PaperweightLazyCompoundTag.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/nbt/PaperweightLazyCompoundTag.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.nbt; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.LazyCompoundTag; diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/regen/PaperweightRegen.java similarity index 69% rename from worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/regen/PaperweightRegen.java rename to worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/regen/PaperweightRegen.java index 8403d531d..e21e7eef7 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/regen/PaperweightRegen.java @@ -1,17 +1,15 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.regen; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.regen; import com.fastasyncworldedit.bukkit.adapter.Regenerator; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.queue.IChunkCache; import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.util.ReflectionUtils; import com.fastasyncworldedit.core.util.TaskManager; import com.google.common.collect.ImmutableList; -import com.mojang.datafixers.util.Either; import com.mojang.serialization.Lifecycle; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.PaperweightGetBlocks; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.PaperweightGetBlocks; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.regions.Region; @@ -20,14 +18,19 @@ import com.sk89q.worldedit.world.RegenOptions; import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import net.minecraft.core.Holder; import net.minecraft.core.Registry; -import net.minecraft.data.BuiltinRegistries; +import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.util.thread.ProcessorHandle; +import net.minecraft.util.thread.ProcessorMailbox; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelHeightAccessor; @@ -37,31 +40,34 @@ import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.biome.FixedBiomeSource; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkGenerator; -import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.WorldGenContext; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; -import net.minecraft.world.level.levelgen.WorldGenSettings; +import net.minecraft.world.level.levelgen.WorldOptions; import net.minecraft.world.level.levelgen.blending.BlendingData; import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PrimaryLevelData; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_18_R2.CraftServer; -import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_18_R2.generator.CustomChunkGenerator; +import org.bukkit.Chunk; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.BlockPopulator; +import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; -import java.io.IOException; import java.lang.reflect.Field; import java.nio.file.Path; import java.util.Collections; @@ -74,6 +80,8 @@ import java.util.concurrent.CompletableFuture; import java.util.function.BooleanSupplier; import java.util.function.Supplier; +import static net.minecraft.core.registries.Registries.BIOME; + public class PaperweightRegen extends Regenerator { private static final Logger LOGGER = LogManagerCompat.getLogger(); @@ -85,6 +93,7 @@ public class PaperweightRegen extends Regenerator) () -> new ServerLevel( @@ -232,66 +254,70 @@ public class PaperweightRegen extends Regenerator singleBiome = options.hasBiomeType() ? BuiltinRegistries.BIOME.asHolderIdMap().byId( - WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) - ) : null; + + private final Holder singleBiome = options.hasBiomeType() ? DedicatedServer.getServer().registryAccess() + .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( + WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) + ) : null; @Override - public void tick(BooleanSupplier shouldKeepTicking) { //no ticking + public void tick(@NotNull BooleanSupplier shouldKeepTicking) { //no ticking } @Override - public Holder getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { + public @NotNull Holder getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { if (options.hasBiomeType()) { return singleBiome; } - return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome(biomeX, biomeY, biomeZ, - PaperweightRegen.this.chunkGenerator.climateSampler() + return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome( + biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler() ); } + }).get(); freshWorld.noSave = true; removeWorldFromWorldsMap(); newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name if (paperConfigField != null) { - paperConfigField.set(freshWorld, originalServerWorld.paperConfig); + paperConfigField.set(freshWorld, originalServerWorld.paperConfig()); } - //generator ChunkGenerator originalGenerator = originalChunkProvider.getGenerator(); if (originalGenerator instanceof FlatLevelSource flatLevelSource) { FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings(); - chunkGenerator = new FlatLevelSource(originalGenerator.structureSets, generatorSettingFlat); + chunkGenerator = new FlatLevelSource(generatorSettingFlat); } else if (originalGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) { - Holder generatorSettingBaseSupplier = - (Holder) generatorSettingBaseSupplierField - .get(originalGenerator); + Holder generatorSettingBaseSupplier = (Holder) + generatorSettingBaseSupplierField.get(noiseBasedChunkGenerator); BiomeSource biomeSource; if (options.hasBiomeType()) { - biomeSource = new FixedBiomeSource(BuiltinRegistries.BIOME - .asHolderIdMap() - .byId(WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()))); + biomeSource = new FixedBiomeSource( + DedicatedServer.getServer().registryAccess() + .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( + WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) + ) + ); } else { biomeSource = originalGenerator.getBiomeSource(); } - chunkGenerator = new NoiseBasedChunkGenerator(originalGenerator.structureSets, noiseBasedChunkGenerator.noises, - biomeSource, seed, + chunkGenerator = new NoiseBasedChunkGenerator( + biomeSource, generatorSettingBaseSupplier ); } else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) { - chunkGenerator = customChunkGenerator.delegate; + chunkGenerator = customChunkGenerator.getDelegate(); } else { LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName()); return false; @@ -300,22 +326,8 @@ public class PaperweightRegen extends Regenerator>> ringPositions = - (Map>>) ringPositionsField.get( - originalGenerator); - Map>> copy = new Object2ObjectArrayMap<>(ringPositions); - ringPositionsField.set(chunkGenerator, copy); - hasGeneratedPositionsField.setBoolean(chunkGenerator, true); - } - } - - - chunkGenerator.conf = originalServerWorld.spigotConfig; freshChunkProvider = new ServerChunkCache( freshWorld, session, @@ -333,7 +345,7 @@ public class PaperweightRegen extends Regenerator>> origPositions = + (Map>>) ringPositionsField.get(state); + Map>> copy = new Object2ObjectArrayMap<>( + origPositions); + ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get( + freshChunkProvider.chunkMap); + ringPositionsField.set(newState, copy); + hasGeneratedPositionsField.setBoolean(newState, true); + } + } + + chunkSourceField.set(freshWorld, freshChunkProvider); //let's start then - structureManager = server.getStructureManager(); - threadedLevelLightEngine = freshChunkProvider.getLightEngine(); + structureTemplateManager = server.getStructureManager(); + threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider); + this.worldGenContext = new WorldGenContext(freshWorld, chunkGenerator, structureTemplateManager, + threadedLevelLightEngine + ); return true; } @@ -362,7 +395,7 @@ public class PaperweightRegen extends Regenerator { try { freshChunkProvider.close(false); - } catch (IOException e) { + } catch (Exception e) { throw new RuntimeException(e); } }); @@ -385,7 +418,7 @@ public class PaperweightRegen extends Regenerator blockPopulator.populate(freshWorld.getWorld(), random, levelChunk.getBukkitChunk())); + TaskManager.taskManager().task(() -> { + final CraftWorld world = freshWorld.getWorld(); + final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ); + blockPopulator.populate(world, random, chunk); + }); } @Override @@ -427,14 +464,12 @@ public class PaperweightRegen extends Regenerator { - try { - Map map = (Map) serverWorldsField.get(Bukkit.getServer()); - map.remove("faweregentempworld"); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - }); + try { + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); + map.remove("faweregentempworld"); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } } private ResourceKey getWorldDimKey(org.bukkit.World.Environment env) { @@ -451,11 +486,15 @@ public class PaperweightRegen extends Regenerator getEntities() { + public @NotNull List getEntities() { return Collections.emptyList(); } @@ -516,23 +554,41 @@ public class PaperweightRegen extends Regenerator processChunk(List accessibleChunks) { return chunkStatus.generate( - Runnable::run, // TODO revisit, we might profit from this somehow? - freshWorld, - chunkGenerator, - structureManager, - threadedLevelLightEngine, - c -> CompletableFuture.completedFuture(Either.left(c)), - accessibleChunks, - true + worldGenContext, + Runnable::run, + CompletableFuture::completedFuture, + accessibleChunks ); } } + /** + * A light engine that does nothing. As light is calculated after pasting anyway, we can avoid + * work this way. + */ + static class NoOpLightEngine extends ThreadedLevelLightEngine { + + private static final ProcessorMailbox MAILBOX = ProcessorMailbox.create(task -> { + }, "fawe-no-op"); + private static final ProcessorHandle> HANDLE = ProcessorHandle.of("fawe-no-op", m -> { + }); + + public NoOpLightEngine(final ServerChunkCache chunkProvider) { + super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE); + } + + @Override + public @NotNull CompletableFuture lightChunk(final @NotNull ChunkAccess chunk, final boolean excludeBlocks) { + return CompletableFuture.completedFuture(chunk); + } + + } + } diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index 8705c931c..3af5fa04e 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -36,6 +36,7 @@ repositories { name = "Glaremasters" url = uri("https://repo.glaremasters.me/repository/towny/") } + maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") // TODO Remove when 4.17.0 is released flatDir { dir(File("src/main/resources")) } } @@ -210,7 +211,7 @@ tasks { versionNumber.set("${project.version}") versionType.set("release") uploadFile.set(file("build/libs/${rootProject.name}-Bukkit-${project.version}.jar")) - gameVersions.addAll(listOf("1.20.4", "1.20.3", "1.20.2", "1.20.1", "1.20", "1.19.4", "1.18.2")) + gameVersions.addAll(listOf("1.20.6", "1.20.5", "1.20.3", "1.20.2", "1.20.1", "1.20", "1.19.4")) loaders.addAll(listOf("paper", "spigot")) changelog.set("The changelog is available on GitHub: https://github.com/IntellectualSites/" + "FastAsyncWorldEdit/releases/tag/${project.version}") diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java index 607bc75bf..2a006d141 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java @@ -5,6 +5,7 @@ import com.fastasyncworldedit.core.queue.IChunkCache; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.SingleThreadQueueExtent; import com.fastasyncworldedit.core.util.MathMan; +import com.google.common.collect.Lists; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.bukkit.BukkitAdapter; @@ -24,11 +25,16 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.LongArrayList; import it.unimi.dsi.fastutil.longs.LongList; +import jdk.jfr.Category; +import jdk.jfr.Event; +import jdk.jfr.Label; +import jdk.jfr.Name; import org.apache.logging.log4j.Logger; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.WorldInfo; +import java.util.AbstractList; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -36,6 +42,7 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Random; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; @@ -62,7 +69,7 @@ public abstract class Regenerator chunkStatuses = new LinkedHashMap<>(); + protected final LinkedHashMap chunkStatuses = new LinkedHashMap<>(); // TODO (j21): use SequencedMap private final Long2ObjectLinkedOpenHashMap protoChunks = new Long2ObjectLinkedOpenHashMap<>(); private final Long2ObjectOpenHashMap chunks = new Long2ObjectOpenHashMap<>(); protected boolean generateConcurrent = true; @@ -172,51 +179,70 @@ public abstract class Regenerator chunkCoordsForRadius = new Int2ObjectOpenHashMap<>(); - chunkStatuses.keySet().stream().mapToInt(ChunkStatusWrapper::requiredNeighborChunkRadius0).distinct().forEach(radius -> { - if (radius == -1) { //ignore ChunkStatus.EMPTY - return; - } - int border = 10 - radius; //9 = 8 + 1, 8: max border radius used in chunk stages, 1: need 1 extra chunk for chunk - // features to generate at the border of the region - chunkCoordsForRadius.put(radius, getChunkCoordsRegen(region, border)); - }); + // to get the chunks we need to generate in the nth chunk status, we need to know how many chunks + // we need to generate in the n + 1 th chunk status. Summing up the margin solves that + LinkedHashMap chunkCoordsForChunkStatus = new LinkedHashMap<>(); + int borderSum = 1; + // TODO (j21): use SequencedMap#sequencedKeySet().reversed() + final List reversedKeys = Lists.reverse(new ArrayList<>(chunkStatuses.keySet())); + for (final ChunkStatus status : reversedKeys) { + chunkCoordsForChunkStatus.put(status, getChunkCoordsRegen(region, borderSum)); + borderSum += status.requiredNeighborChunkRadius(); + } //create chunks - for (long xz : chunkCoordsForRadius.get(0)) { + // TODO (j21): use SequencedMap#firstEntry().getKey() + for (long xz : chunkCoordsForChunkStatus.get(chunkStatuses.keySet().iterator().next())) { ProtoChunk chunk = createProtoChunk(MathMan.unpairIntX(xz), MathMan.unpairIntY(xz)); protoChunks.put(xz, chunk); } - //generate lists for RegionLimitedWorldAccess, need to be square with odd length (e.g. 17x17), 17 = 1 middle chunk + 8 border chunks * 2 - Int2ObjectOpenHashMap>> worldLimits = new Int2ObjectOpenHashMap<>(); - chunkStatuses.keySet().stream().mapToInt(ChunkStatusWrapper::requiredNeighborChunkRadius0).distinct().forEach(radius -> { - if (radius == -1) { //ignore ChunkStatus.EMPTY - return; + // a memory-efficient, lightweight "list" that calculates index -> ChunkAccess + // as needed when accessed + class LazyChunkList extends AbstractList { + private final int size; + private final int minX; + private final int minZ; + private final int sizeSqrt; + + LazyChunkList(int radius, int centerX, int centerZ) { + this.sizeSqrt = radius + 1 + radius; // length of one side + this.size = this.sizeSqrt * this.sizeSqrt; + this.minX = centerX - radius; + this.minZ = centerZ - radius; } - Long2ObjectOpenHashMap> map = new Long2ObjectOpenHashMap<>(); - for (long xz : chunkCoordsForRadius.get(radius)) { - int x = MathMan.unpairIntX(xz); - int z = MathMan.unpairIntY(xz); - List l = new ArrayList<>((radius + 1 + radius) * (radius + 1 + radius)); - for (int zz = z - radius; zz <= z + radius; zz++) { //order is important, first z then x - for (int xx = x - radius; xx <= x + radius; xx++) { - l.add(protoChunks.get(MathMan.pairInt(xx, zz))); - } - } - map.put(xz, l); + @Override + public IChunkAccess get(final int index) { + Objects.checkIndex(index, size); + int absX = (index % sizeSqrt) + minX; + int absZ = (index / sizeSqrt) + minZ; + return protoChunks.get(MathMan.pairInt(absX, absZ)); } - worldLimits.put(radius, map); - }); + + @Override + public int size() { + return size; + } + + } + @Label("Regeneration") + @Category("FAWE") + @Name("fawe.regen") + class RegenerationEvent extends Event { + private String chunkStatus; + private int chunksToProcess; + } //run generation tasks excluding FULL chunk status for (Map.Entry entry : chunkStatuses.entrySet()) { ChunkStatus chunkStatus = entry.getKey(); - int radius = chunkStatus.requiredNeighborChunkRadius0(); + final RegenerationEvent event = new RegenerationEvent(); + event.begin(); + event.chunkStatus = chunkStatus.name(); + int radius = Math.max(1, chunkStatus.requiredNeighborChunkRadius0()); - long[] coords = chunkCoordsForRadius.get(radius); - Long2ObjectOpenHashMap> limitsForRadius = worldLimits.get(radius); + long[] coords = chunkCoordsForChunkStatus.get(chunkStatus); + event.chunksToProcess = coords.length; if (this.generateConcurrent && entry.getValue() == Concurrency.RADIUS) { SequentialTasks> tasks = getChunkStatusTaskRows(coords, radius); for (ConcurrentTasks para : tasks) { @@ -224,7 +250,8 @@ public abstract class Regenerator { for (long xz : row) { - chunkStatus.processChunkSave(xz, limitsForRadius.get(xz)); + chunkStatus.processChunkSave(xz, new LazyChunkList(radius, MathMan.unpairIntX(xz), + MathMan.unpairIntY(xz))); } }); } @@ -234,7 +261,8 @@ public abstract class Regenerator scheduled = new ArrayList<>(coords.length); for (long xz : coords) { - scheduled.add(() -> chunkStatus.processChunkSave(xz, limitsForRadius.get(xz))); + scheduled.add(() -> chunkStatus.processChunkSave(xz, new LazyChunkList(radius, MathMan.unpairIntX(xz), + MathMan.unpairIntY(xz)))); } runAndWait(scheduled); } else { // Concurrency.NONE or generateConcurrent == false @@ -242,28 +270,33 @@ public abstract class Regenerator { for (long xz : coords) { - chunkStatus.processChunkSave(xz, limitsForRadius.get(xz)); + chunkStatus.processChunkSave(xz, new LazyChunkList(radius, MathMan.unpairIntX(xz), + MathMan.unpairIntY(xz))); } }).get(); // wait until finished this step } + event.commit(); } //convert to proper chunks - for (long xz : chunkCoordsForRadius.get(0)) { + // TODO (j21): use SequencedMap#firstEntry().getValue() + for (long xz : chunkCoordsForChunkStatus.values().iterator().next()) { ProtoChunk proto = protoChunks.get(xz); chunks.put(xz, createChunk(proto)); } //final chunkstatus ChunkStatus FULL = getFullChunkStatus(); - for (long xz : chunkCoordsForRadius.get(0)) { //FULL.requiredNeighbourChunkRadius() == 0! + // TODO (j21): use SequencedMap#firstEntry().getValue() + for (long xz : chunkCoordsForChunkStatus.values().iterator().next()) { //FULL.requiredNeighbourChunkRadius() == 0! Chunk chunk = chunks.get(xz); FULL.processChunkSave(xz, List.of(chunk)); } //populate List populators = getBlockPopulators(); - for (long xz : chunkCoordsForRadius.get(0)) { + // TODO (j21): use SequencedMap#firstEntry().getValue() + for (long xz : chunkCoordsForChunkStatus.values().iterator().next()) { int x = MathMan.unpairIntX(xz); int z = MathMan.unpairIntY(xz); @@ -277,8 +310,10 @@ public abstract class Regenerator byZ = new Int2ObjectOpenHashMap<>(); - int expectedListLength = (coordsCount + 1) / (maxZ - minZ); + int expectedListLength = (coordsCount + 1) / (maxZ - minZ + 2); //init lists for (int i = minZ; i <= maxZ; i++) { @@ -581,13 +616,16 @@ public abstract class Regenerator extends Tasks { diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/listener/ChunkListener.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/listener/ChunkListener.java index 7b9599084..91ec973bb 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/listener/ChunkListener.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/listener/ChunkListener.java @@ -135,7 +135,7 @@ public abstract class ChunkListener implements Listener { @Deprecated(since = "2.0.0") public void cleanup(Chunk chunk) { for (Entity entity : chunk.getEntities()) { - if (entity.getType() == EntityType.DROPPED_ITEM) { + if (entity.getType() == EntityType.ITEM) { entity.remove(); } } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/CommandRegistration.java b/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/CommandRegistration.java index 424325127..c650975c3 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/CommandRegistration.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/CommandRegistration.java @@ -20,6 +20,7 @@ package com.sk89q.bukkit.util; import com.sk89q.util.ReflectionUtil; +import io.papermc.lib.PaperLib; import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -96,12 +97,11 @@ public class CommandRegistration { return fallbackCommands; } - CommandMap commandMap = ReflectionUtil.getField(plugin.getServer().getPluginManager(), "commandMap"); + CommandMap commandMap = PaperLib.isPaper() ? Bukkit.getCommandMap() : ReflectionUtil.getField(plugin.getServer().getPluginManager(), "commandMap"); if (commandMap == null) { Bukkit.getServer().getLogger().severe(plugin.getDescription().getName() - + ": Could not retrieve server CommandMap, using fallback instead!"); - fallbackCommands = commandMap = new SimpleCommandMap(Bukkit.getServer()); - Bukkit.getServer().getPluginManager().registerEvents(new FallbackRegistrationListener(fallbackCommands), plugin); + + ": Could not retrieve server CommandMap"); + throw new IllegalStateException("Failed to retrieve command map, make sure you are running supported server software"); } else { serverCommandMap = commandMap; } diff --git a/worldedit-core/doctools/build.gradle.kts b/worldedit-core/doctools/build.gradle.kts index 6f2123f20..cf1cf33de 100644 --- a/worldedit-core/doctools/build.gradle.kts +++ b/worldedit-core/doctools/build.gradle.kts @@ -1,16 +1,12 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - kotlin("jvm") version "1.8.20" + kotlin("jvm") version "1.9.23" application } applyCommonConfiguration() -tasks.withType { - kotlinOptions.jvmTarget = "17" -} - application.mainClass.set("com.sk89q.worldedit.internal.util.DocumentationPrinter") tasks.named("run") { workingDir = rootProject.projectDir diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEditManifest.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEditManifest.java index 9ce5c24f0..449e08db3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEditManifest.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEditManifest.java @@ -23,7 +23,7 @@ import javax.annotation.Nullable; import java.io.IOException; import java.io.UncheckedIOException; import java.net.JarURLConnection; -import java.net.URL; +import java.net.URI; import java.util.function.Supplier; import java.util.jar.Attributes; import java.util.jar.Manifest; @@ -73,8 +73,7 @@ public class WorldEditManifest { } try { - URL url = new URL(classPath); - JarURLConnection jarConnection = (JarURLConnection) url.openConnection(); + JarURLConnection jarConnection = (JarURLConnection) URI.create(classPath).toURL().openConnection(); Manifest manifest = jarConnection.getManifest(); return manifest.getMainAttributes(); } catch (IOException e) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java index ceb07a71e..235cdf761 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java @@ -56,6 +56,7 @@ public class BaseEntity implements NbtValued { * @param nbtData NBT data * @deprecated Use {@link BaseEntity#BaseEntity(EntityType, LazyReference)} */ + @SuppressWarnings("this-escape") @Deprecated public BaseEntity(EntityType type, CompoundTag nbtData) { this(type); @@ -87,6 +88,7 @@ public class BaseEntity implements NbtValued { * * @param other the object to clone */ + @SuppressWarnings("this-escape") public BaseEntity(BaseEntity other) { checkNotNull(other); this.type = other.getType(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/validation/BlockChangeLimiter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/validation/BlockChangeLimiter.java index 498e5ce9f..38b79dc34 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/validation/BlockChangeLimiter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/validation/BlockChangeLimiter.java @@ -62,6 +62,7 @@ public class BlockChangeLimiter extends AbstractDelegateExtent { * * @param limit the limit (>= 0) or -1 for no limit */ + @SuppressWarnings("this-escape") // Unlikely anyone is extending this in practice public void setLimit(int limit) { checkArgument(limit >= -1, "limit >= -1 required"); this.limit = limit; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/ForwardSeekableInputStream.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/ForwardSeekableInputStream.java index 585eaa00e..47f17781f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/ForwardSeekableInputStream.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/ForwardSeekableInputStream.java @@ -19,11 +19,16 @@ package com.sk89q.worldedit.util.io; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + import java.io.IOException; import java.io.InputStream; public class ForwardSeekableInputStream extends InputStream { + private static final Logger LOGGER = LogManager.getLogger(); + protected InputStream parent; protected long position = 0; @@ -60,7 +65,7 @@ public class ForwardSeekableInputStream extends InputStream { @Override public int read(byte[] b, int off, int len) throws IOException { - int read = super.read(b, off, len); + int read = parent.read(b, off, len); position += read; return read; } @@ -86,6 +91,7 @@ public class ForwardSeekableInputStream extends InputStream { public void seek(long n) throws IOException { long diff = n - position; + LOGGER.error("Seek to {} from {} using {}", n, position, diff); if (diff < 0) { throw new IOException("Can't seek backwards"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/net/HttpRequest.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/net/HttpRequest.java index a5c9fdced..d133eb54e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/net/HttpRequest.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/net/HttpRequest.java @@ -357,7 +357,7 @@ public class HttpRequest implements Closeable { */ public static URL url(String url) { try { - return new URL(url); + return URI.create(url).toURL(); } catch (MalformedURLException e) { throw new RuntimeException(e); } @@ -371,13 +371,7 @@ public class HttpRequest implements Closeable { */ private static URL reformat(URL existing) { try { - URL url = new URL(existing.toString()); - URI uri = new URI( - url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), - url.getPath(), url.getQuery(), url.getRef() - ); - url = uri.toURL(); - return url; + return existing.toURI().toURL(); } catch (MalformedURLException | URISyntaxException e) { return existing; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java index 037cea727..1decfd384 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java @@ -24,6 +24,7 @@ import com.google.gson.reflect.TypeToken; import com.sk89q.worldedit.util.net.HttpRequest; import java.io.IOException; +import java.net.URI; import java.net.URL; import java.util.Map; import java.util.concurrent.Callable; @@ -83,7 +84,7 @@ public class EngineHubPaste implements Paster { .execute() .expectResponseCode(200, 204); - return new URL(response.viewUrl); + return URI.create(response.viewUrl).toURL(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/task/FutureForwardingTask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/task/FutureForwardingTask.java index fcf0bd661..515d4d53b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/task/FutureForwardingTask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/task/FutureForwardingTask.java @@ -82,21 +82,22 @@ public class FutureForwardingTask extends AbstractTask { return future.get(timeout, unit); } + // TODO: consider deprecating in favor of Future.State? @Override - public State getState() { + public Task.State getState() { if (isCancelled()) { - return State.CANCELLED; + return Task.State.CANCELLED; } else if (isDone()) { try { get(); - return State.SUCCEEDED; + return Task.State.SUCCEEDED; } catch (InterruptedException e) { - return State.CANCELLED; + return Task.State.CANCELLED; } catch (ExecutionException e) { - return State.FAILED; + return Task.State.FAILED; } } else { - return State.RUNNING; + return Task.State.RUNNING; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java index 4d1bde5f8..7d09d509e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java @@ -33,8 +33,10 @@ public final class BlockCategories { public static final BlockCategory ANCIENT_CITY_REPLACEABLE = get("minecraft:ancient_city_replaceable"); public static final BlockCategory ANIMALS_SPAWNABLE_ON = get("minecraft:animals_spawnable_on"); public static final BlockCategory ANVIL = get("minecraft:anvil"); + public static final BlockCategory ARMADILLO_SPAWNABLE_ON = get("minecraft:armadillo_spawnable_on"); public static final BlockCategory AXOLOTLS_SPAWNABLE_ON = get("minecraft:axolotls_spawnable_on"); public static final BlockCategory AZALEA_GROWS_ON = get("minecraft:azalea_grows_on"); + public static final BlockCategory BADLANDS_TERRACOTTA = get("minecraft:badlands_terracotta"); public static final BlockCategory AZALEA_ROOT_REPLACEABLE = get("minecraft:azalea_root_replaceable"); public static final BlockCategory BAMBOO_BLOCKS = get("minecraft:bamboo_blocks"); public static final BlockCategory BAMBOO_PLANTABLE_ON = get("minecraft:bamboo_plantable_on"); @@ -78,6 +80,7 @@ public final class BlockCategories { public static final BlockCategory DIRT = get("minecraft:dirt"); @Deprecated public static final BlockCategory DIRT_LIKE = get("minecraft:dirt_like"); + public static final BlockCategory DOES_NOT_BLOCK_HOPPERS = get("minecraft:does_not_block_hoppers"); public static final BlockCategory DOORS = get("minecraft:doors"); public static final BlockCategory DRAGON_IMMUNE = get("minecraft:dragon_immune"); public static final BlockCategory DRAGON_TRANSPARENT = get("minecraft:dragon_transparent"); @@ -103,6 +106,12 @@ public final class BlockCategories { public static final BlockCategory HOGLIN_REPELLENTS = get("minecraft:hoglin_repellents"); public static final BlockCategory ICE = get("minecraft:ice"); public static final BlockCategory IMPERMEABLE = get("minecraft:impermeable"); + public static final BlockCategory INCORRECT_FOR_DIAMOND_TOOL = get("minecraft:incorrect_for_diamond_tool"); + public static final BlockCategory INCORRECT_FOR_GOLD_TOOL = get("minecraft:incorrect_for_gold_tool"); + public static final BlockCategory INCORRECT_FOR_IRON_TOOL = get("minecraft:incorrect_for_iron_tool"); + public static final BlockCategory INCORRECT_FOR_NETHERITE_TOOL = get("minecraft:incorrect_for_netherite_tool"); + public static final BlockCategory INCORRECT_FOR_STONE_TOOL = get("minecraft:incorrect_for_stone_tool"); + public static final BlockCategory INCORRECT_FOR_WOODEN_TOOL = get("minecraft:incorrect_for_wooden_tool"); public static final BlockCategory INFINIBURN_END = get("minecraft:infiniburn_end"); public static final BlockCategory INFINIBURN_NETHER = get("minecraft:infiniburn_nether"); public static final BlockCategory INFINIBURN_OVERWORLD = get("minecraft:infiniburn_overworld"); 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 7762ee532..a2e58a97c 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 @@ -60,6 +60,7 @@ public class BlockType implements Keyed, Pattern { private static final Logger LOGGER = LogManagerCompat.getLogger(); private final String id; + @SuppressWarnings("this-escape") private final LazyReference emptyFuzzy = LazyReference.from(() -> new FuzzyBlockState(this)); //FAWE start 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 513a00557..0206cdf92 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 @@ -908,6 +908,8 @@ public final class BlockTypes { @Nullable public static final BlockType HAY_BLOCK = init(); @Nullable + public static final BlockType HEAVY_CORE = init(); + @Nullable public static final BlockType HEAVY_WEIGHTED_PRESSURE_PLATE = init(); @Nullable public static final BlockType HONEYCOMB_BLOCK = init(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java index e1cb08bc8..9b0d764f1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java @@ -163,7 +163,7 @@ public class AnvilChunk13 implements Chunk { throw new InvalidFormatException("Too short block state table"); } currentSerializedValue = blockStatesSerialized[nextSerializedItem++]; - localBlockId |= (currentSerializedValue & ((1 << bitsNextLong) - 1)) << remainingBits; + localBlockId |= (int) ((currentSerializedValue & ((1 << bitsNextLong) - 1)) << remainingBits); currentSerializedValue >>>= bitsNextLong; remainingBits = 64 - bitsNextLong; } else { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java index f981593fe..52044abdf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java @@ -35,6 +35,8 @@ public final class EntityTypes { @Nullable public static final EntityType AREA_EFFECT_CLOUD = get("minecraft:area_effect_cloud"); @Nullable + public static final EntityType ARMADILLO = get("minecraft:armadillo"); + @Nullable public static final EntityType ARMOR_STAND = get("minecraft:armor_stand"); @Nullable public static final EntityType ARROW = get("minecraft:arrow"); @@ -51,8 +53,12 @@ public final class EntityTypes { @Nullable public static final EntityType BOAT = get("minecraft:boat"); @Nullable + public static final EntityType BOGGED = get("minecraft:bogged"); + @Nullable public static final EntityType BREEZE = get("minecraft:breeze"); @Nullable + public static final EntityType BREEZE_WIND_CHARGE = get("minecraft:breeze_wind_charge"); + @Nullable public static final EntityType CAMEL = get("minecraft:camel"); @Nullable public static final EntityType CAT = get("minecraft:cat"); @@ -171,6 +177,8 @@ public final class EntityTypes { @Nullable public static final EntityType OCELOT = get("minecraft:ocelot"); @Nullable + public static final EntityType OMINOUS_ITEM_SPAWNER = get("minecraft:ominous_item_spawner"); + @Nullable public static final EntityType PAINTING = get("minecraft:painting"); @Nullable public static final EntityType PANDA = get("minecraft:panda"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemCategories.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemCategories.java index 3b6bdc6b6..466db6fdd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemCategories.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemCategories.java @@ -29,28 +29,36 @@ public final class ItemCategories { public static final ItemCategory ACACIA_LOGS = get("minecraft:acacia_logs"); public static final ItemCategory ANVIL = get("minecraft:anvil"); + public static final ItemCategory ARMADILLO_FOOD = get("minecraft:armadillo_food"); public static final ItemCategory ARROWS = get("minecraft:arrows"); public static final ItemCategory AXES = get("minecraft:axes"); - public static final ItemCategory AXOLOTL_TEMPT_ITEMS = get("minecraft:axolotl_tempt_items"); + public static final ItemCategory AXOLOTL_FOOD = get("minecraft:axolotl_food"); + @Deprecated public static final ItemCategory AXOLOTL_TEMPT_ITEMS = get("minecraft:axolotl_tempt_items"); public static final ItemCategory BAMBOO_BLOCKS = get("minecraft:bamboo_blocks"); public static final ItemCategory BANNERS = get("minecraft:banners"); public static final ItemCategory BEACON_PAYMENT_ITEMS = get("minecraft:beacon_payment_items"); public static final ItemCategory BEDS = get("minecraft:beds"); + public static final ItemCategory BEE_FOOD = get("minecraft:bee_food"); public static final ItemCategory BIRCH_LOGS = get("minecraft:birch_logs"); public static final ItemCategory BOATS = get("minecraft:boats"); public static final ItemCategory BOOKSHELF_BOOKS = get("minecraft:bookshelf_books"); public static final ItemCategory BREAKS_DECORATED_POTS = get("minecraft:breaks_decorated_pots"); public static final ItemCategory BUTTONS = get("minecraft:buttons"); + public static final ItemCategory CAMEL_FOOD = get("minecraft:camel_food"); public static final ItemCategory CANDLES = get("minecraft:candles"); @Deprecated public static final ItemCategory CARPETS = get("minecraft:carpets"); + public static final ItemCategory CAT_FOOD = get("minecraft:cat_food"); public static final ItemCategory CHERRY_LOGS = get("minecraft:cherry_logs"); + public static final ItemCategory CHEST_ARMOR = get("minecraft:chest_armor"); public static final ItemCategory CHEST_BOATS = get("minecraft:chest_boats"); + public static final ItemCategory CHICKEN_FOOD = get("minecraft:chicken_food"); public static final ItemCategory CLUSTER_MAX_HARVESTABLES = get("minecraft:cluster_max_harvestables"); public static final ItemCategory COAL_ORES = get("minecraft:coal_ores"); public static final ItemCategory COALS = get("minecraft:coals"); public static final ItemCategory COMPASSES = get("minecraft:compasses"); public static final ItemCategory COMPLETES_FIND_TREE_TUTORIAL = get("minecraft:completes_find_tree_tutorial"); public static final ItemCategory COPPER_ORES = get("minecraft:copper_ores"); + public static final ItemCategory COW_FOOD = get("minecraft:cow_food"); public static final ItemCategory CREEPER_DROP_MUSIC_DISCS = get("minecraft:creeper_drop_music_discs"); public static final ItemCategory CREEPER_IGNITERS = get("minecraft:creeper_igniters"); public static final ItemCategory CRIMSON_STEMS = get("minecraft:crimson_stems"); @@ -61,44 +69,82 @@ public final class ItemCategories { public static final ItemCategory DIAMOND_ORES = get("minecraft:diamond_ores"); public static final ItemCategory DIRT = get("minecraft:dirt"); public static final ItemCategory DOORS = get("minecraft:doors"); + public static final ItemCategory DYEABLE = get("minecraft:dyeable"); public static final ItemCategory EMERALD_ORES = get("minecraft:emerald_ores"); + public static final ItemCategory ENCHANTABLE_ARMOR = get("minecraft:enchantable/armor"); + public static final ItemCategory ENCHANTABLE_BOW = get("minecraft:enchantable/bow"); + public static final ItemCategory ENCHANTABLE_CHEST_ARMOR = get("minecraft:enchantable/chest_armor"); + public static final ItemCategory ENCHANTABLE_CROSSBOW = get("minecraft:enchantable/crossbow"); + public static final ItemCategory ENCHANTABLE_DURABILITY = get("minecraft:enchantable/durability"); + public static final ItemCategory ENCHANTABLE_EQUIPPABLE = get("minecraft:enchantable/equippable"); + public static final ItemCategory ENCHANTABLE_FIRE_ASPECT = get("minecraft:enchantable/fire_aspect"); + public static final ItemCategory ENCHANTABLE_FISHING = get("minecraft:enchantable/fishing"); + public static final ItemCategory ENCHANTABLE_FOOT_ARMOR = get("minecraft:enchantable/foot_armor"); + public static final ItemCategory ENCHANTABLE_HEAD_ARMOR = get("minecraft:enchantable/head_armor"); + public static final ItemCategory ENCHANTABLE_LEG_ARMOR = get("minecraft:enchantable/leg_armor"); + public static final ItemCategory ENCHANTABLE_MINING = get("minecraft:enchantable/mining"); + public static final ItemCategory ENCHANTABLE_MINING_LOOT = get("minecraft:enchantable/mining_loot"); + public static final ItemCategory ENCHANTABLE_SHARP_WEAPON = get("minecraft:enchantable/sharp_weapon"); + public static final ItemCategory ENCHANTABLE_SWORD = get("minecraft:enchantable/sword"); + public static final ItemCategory ENCHANTABLE_TRIDENT = get("minecraft:enchantable/trident"); + public static final ItemCategory ENCHANTABLE_VANISHING = get("minecraft:enchantable/vanishing"); + public static final ItemCategory ENCHANTABLE_WEAPON = get("minecraft:enchantable/weapon"); public static final ItemCategory FENCE_GATES = get("minecraft:fence_gates"); public static final ItemCategory FENCES = get("minecraft:fences"); public static final ItemCategory FISHES = get("minecraft:fishes"); public static final ItemCategory FLOWERS = get("minecraft:flowers"); + public static final ItemCategory FOOT_ARMOR = get("minecraft:foot_armor"); public static final ItemCategory FOX_FOOD = get("minecraft:fox_food"); public static final ItemCategory FREEZE_IMMUNE_WEARABLES = get("minecraft:freeze_immune_wearables"); + public static final ItemCategory FROG_FOOD = get("minecraft:frog_food"); @Deprecated public static final ItemCategory FURNACE_MATERIALS = get("minecraft:furnace_materials"); + public static final ItemCategory GOAT_FOOD = get("minecraft:goat_food"); public static final ItemCategory GOLD_ORES = get("minecraft:gold_ores"); public static final ItemCategory HANGING_SIGNS = get("minecraft:hanging_signs"); + public static final ItemCategory HEAD_ARMOR = get("minecraft:head_armor"); public static final ItemCategory HOES = get("minecraft:hoes"); + public static final ItemCategory HOGLIN_FOOD = get("minecraft:hoglin_food"); + public static final ItemCategory HORSE_FOOD = get("minecraft:horse_food"); + public static final ItemCategory HORSE_TEMPT_ITEMS = get("minecraft:horse_tempt_items"); public static final ItemCategory IGNORED_BY_PIGLIN_BABIES = get("minecraft:ignored_by_piglin_babies"); public static final ItemCategory IRON_ORES = get("minecraft:iron_ores"); public static final ItemCategory JUNGLE_LOGS = get("minecraft:jungle_logs"); public static final ItemCategory LAPIS_ORES = get("minecraft:lapis_ores"); public static final ItemCategory LEAVES = get("minecraft:leaves"); public static final ItemCategory LECTERN_BOOKS = get("minecraft:lectern_books"); + public static final ItemCategory LEG_ARMOR = get("minecraft:leg_armor"); + public static final ItemCategory LLAMA_FOOD = get("minecraft:llama_food"); + public static final ItemCategory LLAMA_TEMPT_ITEMS = get("minecraft:llama_tempt_items"); public static final ItemCategory LOGS = get("minecraft:logs"); public static final ItemCategory LOGS_THAT_BURN = get("minecraft:logs_that_burn"); public static final ItemCategory MANGROVE_LOGS = get("minecraft:mangrove_logs"); + public static final ItemCategory MEAT = get("minecraft:meat"); public static final ItemCategory MUSIC_DISCS = get("minecraft:music_discs"); public static final ItemCategory NON_FLAMMABLE_WOOD = get("minecraft:non_flammable_wood"); public static final ItemCategory NOTEBLOCK_TOP_INSTRUMENTS = get("minecraft:noteblock_top_instruments"); public static final ItemCategory OAK_LOGS = get("minecraft:oak_logs"); @Deprecated public static final ItemCategory OCCLUDES_VIBRATION_SIGNALS = get("minecraft:occludes_vibration_signals"); + public static final ItemCategory OCELOT_FOOD = get("minecraft:ocelot_food"); @Deprecated public static final ItemCategory OVERWORLD_NATURAL_LOGS = get("minecraft:overworld_natural_logs"); + public static final ItemCategory PANDA_FOOD = get("minecraft:panda_food"); + public static final ItemCategory PARROT_FOOD = get("minecraft:parrot_food"); + public static final ItemCategory PARROT_POISONOUS_FOOD = get("minecraft:parrot_poisonous_food"); public static final ItemCategory PICKAXES = get("minecraft:pickaxes"); + public static final ItemCategory PIG_FOOD = get("minecraft:pig_food"); public static final ItemCategory PIGLIN_FOOD = get("minecraft:piglin_food"); public static final ItemCategory PIGLIN_LOVED = get("minecraft:piglin_loved"); public static final ItemCategory PIGLIN_REPELLENTS = get("minecraft:piglin_repellents"); public static final ItemCategory PLANKS = get("minecraft:planks"); + public static final ItemCategory RABBIT_FOOD = get("minecraft:rabbit_food"); public static final ItemCategory RAILS = get("minecraft:rails"); public static final ItemCategory REDSTONE_ORES = get("minecraft:redstone_ores"); public static final ItemCategory SAND = get("minecraft:sand"); public static final ItemCategory SAPLINGS = get("minecraft:saplings"); + public static final ItemCategory SHEEP_FOOD = get("minecraft:sheep_food"); public static final ItemCategory SHOVELS = get("minecraft:shovels"); public static final ItemCategory SIGNS = get("minecraft:signs"); + public static final ItemCategory SKULLS = get("minecraft:skulls"); public static final ItemCategory SLABS = get("minecraft:slabs"); public static final ItemCategory SMALL_FLOWERS = get("minecraft:small_flowers"); public static final ItemCategory SMELTS_TO_GLASS = get("minecraft:smelts_to_glass"); @@ -110,18 +156,22 @@ public final class ItemCategories { public static final ItemCategory STONE_BUTTONS = get("minecraft:stone_buttons"); public static final ItemCategory STONE_CRAFTING_MATERIALS = get("minecraft:stone_crafting_materials"); public static final ItemCategory STONE_TOOL_MATERIALS = get("minecraft:stone_tool_materials"); + public static final ItemCategory STRIDER_FOOD = get("minecraft:strider_food"); + public static final ItemCategory STRIDER_TEMPT_ITEMS = get("minecraft:strider_tempt_items"); public static final ItemCategory SWORDS = get("minecraft:swords"); public static final ItemCategory TALL_FLOWERS = get("minecraft:tall_flowers"); public static final ItemCategory TERRACOTTA = get("minecraft:terracotta"); - public static final ItemCategory TOOLS = get("minecraft:tools"); + @Deprecated public static final ItemCategory TOOLS = get("minecraft:tools"); public static final ItemCategory TRAPDOORS = get("minecraft:trapdoors"); public static final ItemCategory TRIM_MATERIALS = get("minecraft:trim_materials"); public static final ItemCategory TRIM_TEMPLATES = get("minecraft:trim_templates"); public static final ItemCategory TRIMMABLE_ARMOR = get("minecraft:trimmable_armor"); + public static final ItemCategory TURTLE_FOOD = get("minecraft:turtle_food"); public static final ItemCategory VILLAGER_PLANTABLE_SEEDS = get("minecraft:villager_plantable_seeds"); public static final ItemCategory WALLS = get("minecraft:walls"); public static final ItemCategory WARPED_STEMS = get("minecraft:warped_stems"); public static final ItemCategory WART_BLOCKS = get("minecraft:wart_blocks"); + public static final ItemCategory WOLF_FOOD = get("minecraft:wolf_food"); public static final ItemCategory WOODEN_BUTTONS = get("minecraft:wooden_buttons"); public static final ItemCategory WOODEN_DOORS = get("minecraft:wooden_doors"); public static final ItemCategory WOODEN_FENCES = get("minecraft:wooden_fences"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java index 16a65c308..5dc7f9277 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java @@ -42,7 +42,7 @@ public class ItemType implements RegistryItem, Keyed { public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("item type", true); private final String id; - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "this-escape"}) private transient final LazyReference name = LazyReference.from(() -> { String name = GuavaUtil.firstNonNull( WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS) @@ -51,10 +51,12 @@ public class ItemType implements RegistryItem, Keyed { ); return name.isEmpty() ? getId() : name; }); + @SuppressWarnings("this-escape") private transient final LazyReference richName = LazyReference.from(() -> WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS) .getRegistries().getItemRegistry().getRichName(this) ); + @SuppressWarnings("this-escape") private transient final LazyReference itemMaterial = LazyReference.from(() -> WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS) .getRegistries().getItemRegistry().getMaterial(this) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java index b8064bb94..f3cd6d0cc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java @@ -105,6 +105,10 @@ public final class ItemTypes { @Nullable public static final ItemType ARMOR_STAND = init(); @Nullable + public static final ItemType ARMADILLO_SCUTE = init(); + @Nullable + public static final ItemType ARMADILLO_SPAWN_EGG = init(); + @Nullable public static final ItemType ARMS_UP_POTTERY_SHERD = init(); @Nullable public static final ItemType ARROW = init(); @@ -297,6 +301,10 @@ public final class ItemTypes { @Nullable public static final ItemType BLUE_WOOL = init(); @Nullable + public static final ItemType BOGGED_SPAWN_EGG = init(); + @Nullable + public static final ItemType BOLT_ARMOR_TRIM_SMITHING_TEMPLATE = init(); + @Nullable public static final ItemType BONE = init(); @Nullable public static final ItemType BONE_BLOCK = init(); @@ -319,6 +327,8 @@ public final class ItemTypes { @Nullable public static final ItemType BREAD = init(); @Nullable + public static final ItemType BREEZE_ROD = init(); + @Nullable public static final ItemType BREEZE_SPAWN_EGG = init(); @Nullable public static final ItemType BREWER_POTTERY_SHERD = init(); @@ -971,6 +981,12 @@ public final class ItemTypes { @Nullable public static final ItemType FLINT_AND_STEEL = init(); @Nullable + public static final ItemType FLOW_ARMOR_TRIM_SMITHING_TEMPLATE = init(); + @Nullable + public static final ItemType FLOW_BANNER_PATTERN = init(); + @Nullable + public static final ItemType FLOW_POTTERY_SHERD = init(); + @Nullable public static final ItemType FLOWER_BANNER_PATTERN = init(); @Nullable public static final ItemType FLOWER_POT = init(); @@ -1132,6 +1148,10 @@ public final class ItemTypes { @Nullable public static final ItemType GUNPOWDER = init(); @Nullable + public static final ItemType GUSTER_BANNER_PATTERN = init(); + @Nullable + public static final ItemType GUSTER_POTTERY_SHERD = init(); + @Nullable public static final ItemType HANGING_ROOTS = init(); @Nullable public static final ItemType HAY_BLOCK = init(); @@ -1142,6 +1162,8 @@ public final class ItemTypes { @Nullable public static final ItemType HEARTBREAK_POTTERY_SHERD = init(); @Nullable + public static final ItemType HEAVY_CORE = init(); + @Nullable public static final ItemType HEAVY_WEIGHTED_PRESSURE_PLATE = init(); @Nullable public static final ItemType HOGLIN_SPAWN_EGG = init(); @@ -1404,6 +1426,8 @@ public final class ItemTypes { @Nullable public static final ItemType LOOM = init(); @Nullable + public static final ItemType MACE = init(); + @Nullable public static final ItemType MAGENTA_BANNER = init(); @Nullable public static final ItemType MAGENTA_BED = init(); @@ -1668,6 +1692,10 @@ public final class ItemTypes { @Nullable public static final ItemType OCHRE_FROGLIGHT = init(); @Nullable + public static final ItemType OMINOUS_BOTTLE = init(); + @Nullable + public static final ItemType OMINOUS_TRIAL_KEY = init(); + @Nullable public static final ItemType ORANGE_BANNER = init(); @Nullable public static final ItemType ORANGE_BED = init(); @@ -2075,6 +2103,8 @@ public final class ItemTypes { @Nullable public static final ItemType SCAFFOLDING = init(); @Nullable + public static final ItemType SCRAPE_POTTERY_SHERD = init(); + @Nullable public static final ItemType SCULK = init(); @Nullable public static final ItemType SCULK_CATALYST = init(); @@ -2085,6 +2115,7 @@ public final class ItemTypes { @Nullable public static final ItemType SCULK_VEIN = init(); @Nullable + @Deprecated public static final ItemType SCUTE = init(); @Nullable public static final ItemType SEA_LANTERN = init(); @@ -2424,10 +2455,14 @@ public final class ItemTypes { @Nullable public static final ItemType TURTLE_HELMET = init(); @Nullable + public static final ItemType TURTLE_SCUTE = init(); + @Nullable public static final ItemType TURTLE_SPAWN_EGG = init(); @Nullable public static final ItemType TWISTING_VINES = init(); @Nullable + public static final ItemType VAULT = init(); + @Nullable public static final ItemType VERDANT_FROGLIGHT = init(); @Nullable public static final ItemType VEX_ARMOR_TRIM_SMITHING_TEMPLATE = init(); @@ -2614,6 +2649,8 @@ public final class ItemTypes { @Nullable public static final ItemType WILD_ARMOR_TRIM_SMITHING_TEMPLATE = init(); @Nullable + public static final ItemType WIND_CHARGE = init(); + @Nullable public static final ItemType WITCH_SPAWN_EGG = init(); @Nullable public static final ItemType WITHER_ROSE = init(); @@ -2624,6 +2661,8 @@ public final class ItemTypes { @Nullable public static final ItemType WITHER_SPAWN_EGG = init(); @Nullable + public static final ItemType WOLF_ARMOR = init(); + @Nullable public static final ItemType WOLF_SPAWN_EGG = init(); @Nullable public static final ItemType WOODEN_AXE = init(); From 9a6aa78ae8c6afd947d8c1a68c43d7f633fa167a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 May 2024 14:46:31 +0200 Subject: [PATCH 241/466] Update dependency com.sk89q.worldguard:worldguard-bukkit to v7.0.10 (#2731) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c02ba9098..ec09586f1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,7 @@ snakeyaml = "2.0" # Plugins dummypermscompat = "1.10" -worldguard-bukkit = "7.0.9" +worldguard-bukkit = "7.0.10" mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" From 49ea04574dd6b49dafb58d649be6697cba23dcd0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 May 2024 14:46:38 +0200 Subject: [PATCH 242/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.2.9 (#2730) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ec09586f1..c793b1a49 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.2.8" +towny = "0.100.2.9" plotsquared = "7.3.8" # Third party From 96c324a0acb32ebafd0e54d1bf85e58d29a088de Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 May 2024 14:20:04 +0000 Subject: [PATCH 243/466] Update eps1lon/actions-label-merge-conflict action to v3.0.1 --- .github/workflows/label-merge-conflicts.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-merge-conflicts.yaml b/.github/workflows/label-merge-conflicts.yaml index fa6f3d72d..551b39417 100644 --- a/.github/workflows/label-merge-conflicts.yaml +++ b/.github/workflows/label-merge-conflicts.yaml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Label conflicting PRs - uses: eps1lon/actions-label-merge-conflict@v3.0.0 + uses: eps1lon/actions-label-merge-conflict@v3.0.1 with: dirtyLabel: "unresolved-merge-conflict" repoToken: "${{ secrets.GITHUB_TOKEN }}" From 2285b1dc34452cf891f5d60a856e04601ebd0693 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 May 2024 14:20:09 +0000 Subject: [PATCH 244/466] Update adventure to v4.17.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c793b1a49..dfa177187 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -21,7 +21,7 @@ plotsquared = "7.3.8" bstats = "3.0.2" sparsebitset = "1.3" parallelgzip = "1.0.5" -adventure = "4.16.0" +adventure = "4.17.0" adventure-bukkit = "4.3.2" checkerqual = "3.43.0" truezip = "6.8.4" From adb045be6a034d7a2e87cac5c3b48e66d74f43b4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 May 2024 14:20:15 +0000 Subject: [PATCH 245/466] Update dependency net.kyori:adventure-nbt to v4.17.0 --- worldedit-bukkit/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index 3af5fa04e..ce6c9d1b1 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -179,7 +179,7 @@ tasks.named("shadowJar") { include(dependency("org.lz4:lz4-java:1.8.0")) } relocate("net.kyori", "com.fastasyncworldedit.core.adventure") { - include(dependency("net.kyori:adventure-nbt:4.16.0")) + include(dependency("net.kyori:adventure-nbt:4.17.0")) } relocate("com.zaxxer", "com.fastasyncworldedit.core.math") { include(dependency("com.zaxxer:SparseBitSet:1.3")) From d17beba7bb76eb0711fbd4701155753a52fbc38e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 May 2024 14:19:58 +0000 Subject: [PATCH 246/466] Update dependency paperweight-userdev to v1.20.6-R0.1-20240518.202723-58 --- worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts index e1a518cbb..abac5e94c 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/ - the().paperDevBundle("1.20.6-R0.1-20240516.001739-55") + the().paperDevBundle("1.20.6-R0.1-20240518.202723-58") compileOnly(libs.paperlib) } From 361baef13dfdc7450459f3808248376007010bfd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 May 2024 14:20:21 +0000 Subject: [PATCH 247/466] Update dependency org.mockito:mockito-core to v5.12.0 --- gradle/libs.versions.toml | 2 +- worldedit-sponge/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index dfa177187..639b7b010 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -46,7 +46,7 @@ text = "3.0.4" piston = "0.5.10" # Tests -mockito = "5.11.0" +mockito = "5.12.0" # Gradle plugins pluginyml = "0.6.0" diff --git a/worldedit-sponge/build.gradle.kts b/worldedit-sponge/build.gradle.kts index 6498cca7e..1c3ad6b68 100644 --- a/worldedit-sponge/build.gradle.kts +++ b/worldedit-sponge/build.gradle.kts @@ -28,7 +28,7 @@ dependencies { }) api("org.apache.logging.log4j:log4j-api") api("org.bstats:bstats-sponge:1.7") - testImplementation("org.mockito:mockito-core:5.11.0") + testImplementation("org.mockito:mockito-core:5.12.0") } <<<<<<< HEAD From db6442ad35750e933b1855ca6c4ad67d521adfdb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 May 2024 14:20:28 +0000 Subject: [PATCH 248/466] Update plugin xyz.jpenilla.run-paper to v2.3.0 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index aed748cdb..a57667e8d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,7 +7,7 @@ import xyz.jpenilla.runpaper.task.RunServer plugins { id("io.github.gradle-nexus.publish-plugin") version "2.0.0" - id("xyz.jpenilla.run-paper") version "2.2.4" + id("xyz.jpenilla.run-paper") version "2.3.0" } if (!File("$rootDir/.git").exists()) { From d8eb03f4c1f000cbb496cd3df7e356fcc23be0ab Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 19 May 2024 17:31:14 +0200 Subject: [PATCH 249/466] Release 2.10.0 Signed-off-by: Alexander Brandes --- build.gradle.kts | 4 ++-- buildSrc/src/main/kotlin/CommonJavaConfig.kt | 2 +- .../com/fastasyncworldedit/core/configuration/Config.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index a57667e8d..7c99f1678 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.9.3") +var rootVersion by extra("2.10.0") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s-%s", rootVersion, buildNumber) +version = String.format("%s", rootVersion) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") diff --git a/buildSrc/src/main/kotlin/CommonJavaConfig.kt b/buildSrc/src/main/kotlin/CommonJavaConfig.kt index f915c2e0c..fec02d1a0 100644 --- a/buildSrc/src/main/kotlin/CommonJavaConfig.kt +++ b/buildSrc/src/main/kotlin/CommonJavaConfig.kt @@ -61,7 +61,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean "https://jd.advntr.dev/api/latest/", "https://logging.apache.org/log4j/2.x/javadoc/log4j-api/", "https://www.antlr.org/api/Java/", - "https://jd.papermc.io/paper/1.20/", + "https://jd.papermc.io/paper/1.20.6/", "https://intellectualsites.github.io/fastasyncworldedit-javadocs/worldedit-core/" ) docTitle = "${rootProject.name}-${project.description}" + " " + "${rootProject.version}" diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java index c3f223dc2..e5185e6d8 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java @@ -189,7 +189,7 @@ public class Config { /** * Indicates that a field should be instantiated / created. * - * @since TODO + * @since 2.10.0 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) From 657dbe214607b6ea620f1f357180aa179d60ed18 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 19 May 2024 17:47:26 +0200 Subject: [PATCH 250/466] [ci skip] Back to snapshot for development Signed-off-by: Alexander Brandes --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 7c99f1678..8fdea3200 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.10.0") +var rootVersion by extra("2.10.1") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s", rootVersion) +version = String.format("%s-%s", rootVersion, buildNumber) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From 3dc949e38394dd0599904bf9c55c101cbce69fd0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 20 May 2024 03:33:56 +0000 Subject: [PATCH 251/466] Update dependency paperweight-userdev to v1.20.6-R0.1-20240520.005421-60 --- worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts index abac5e94c..a0ee57dc2 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/ - the().paperDevBundle("1.20.6-R0.1-20240518.202723-58") + the().paperDevBundle("1.20.6-R0.1-20240520.005421-60") compileOnly(libs.paperlib) } From f9c523c1738d9039e49ec1ff86f11bd95098221a Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 24 May 2024 15:09:57 +0200 Subject: [PATCH 252/466] feat: move limits for (brush, superpickaxe and normal) radii to fawe (#2635) - closes #2587 --- .../worldedit/bukkit/WorldEditPlugin.java | 19 +- .../resources/defaults/worldedit-config.yml | 2 + .../core/command/tool/scroll/ScrollRange.java | 2 +- .../core/command/tool/scroll/ScrollSize.java | 2 +- .../core/configuration/Settings.java | 27 ++- .../exception/BrushRadiusLimitException.java | 30 +++ .../core/exception/RadiusLimitException.java | 41 +++++ .../core/limit/FaweLimit.java | 23 ++- .../sk89q/worldedit/LocalConfiguration.java | 30 +++ .../worldedit/MaxBrushRadiusException.java | 15 ++ .../sk89q/worldedit/MaxRadiusException.java | 14 ++ .../java/com/sk89q/worldedit/WorldEdit.java | 57 ++++++ .../worldedit/command/BrushCommands.java | 172 ++++++++++++++---- .../worldedit/command/GenerationCommands.java | 32 ++-- .../command/SuperPickaxeCommands.java | 18 +- .../sk89q/worldedit/command/ToolCommands.java | 9 +- .../worldedit/command/ToolUtilCommands.java | 2 +- .../worldedit/command/UtilityCommands.java | 41 ++--- .../worldedit/command/tool/BrushTool.java | 2 +- .../command/util/annotation/Confirm.java | 2 +- .../WorldEditExceptionConverter.java | 14 ++ .../util/PropertiesConfiguration.java | 8 + .../worldedit/util/YAMLConfiguration.java | 7 + .../src/main/resources/lang/strings.json | 2 + 24 files changed, 470 insertions(+), 101 deletions(-) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/exception/BrushRadiusLimitException.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/exception/RadiusLimitException.java 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 e881416c5..b4556409c 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 @@ -120,7 +120,6 @@ public class WorldEditPlugin extends JavaPlugin { public void onLoad() { //FAWE start - this.bukkitConsoleCommandSender = new BukkitCommandSender(this, Bukkit.getConsoleSender()); // This is already covered by Spigot, however, a more pesky warning with a proper explanation over "Ambiguous plugin name..." can't hurt. Plugin[] plugins = Bukkit.getServer().getPluginManager().getPlugins(); for (Plugin p : plugins) { @@ -138,6 +137,14 @@ public class WorldEditPlugin extends JavaPlugin { //noinspection ResultOfMethodCallIgnored getDataFolder().mkdirs(); + //FAWE start - Modify WorldEdit config name + config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "worldedit-config.yml"), true), this); + // Load config before we say we've loaded platforms as it is used in listeners of the event + // Load config in onLoad to ensure it is loaded before FAWE settings to allow (inelegant) copying of values across + // where needed + config.load(); + //FAWE end + WorldEdit worldEdit = WorldEdit.getInstance(); // Setup platform @@ -148,14 +155,14 @@ public class WorldEditPlugin extends JavaPlugin { migrateLegacyConfig(); //FAWE end - //FAWE start - Modify WorldEdit config name - config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "worldedit-config.yml"), true), this); - //FAWE end - //FAWE start - Setup permission attachments permissionAttachmentManager = new BukkitPermissionAttachmentManager(this); //FAWE end + //FAWE start - initialise bukkitConsoleCommandSender later + this.bukkitConsoleCommandSender = new BukkitCommandSender(this, Bukkit.getConsoleSender()); + //FAWE end + Path delChunks = Paths.get(getDataFolder().getPath(), DELCHUNKS_FILE_NAME); if (Files.exists(delChunks)) { ChunkDeleter.runFromFile(delChunks, true); @@ -189,8 +196,6 @@ public class WorldEditPlugin extends JavaPlugin { new FaweBukkit(this); //FAWE end - config.load(); // Load config before we say we've loaded platforms as it is used in listeners of the event - WorldEdit.getInstance().getEventBus().post(new PlatformsRegisteredEvent()); PermissionsResolverManager.initialize(this); // Setup permission resolver diff --git a/worldedit-bukkit/src/main/resources/defaults/worldedit-config.yml b/worldedit-bukkit/src/main/resources/defaults/worldedit-config.yml index 8140cade6..b74eaa091 100644 --- a/worldedit-bukkit/src/main/resources/defaults/worldedit-config.yml +++ b/worldedit-bukkit/src/main/resources/defaults/worldedit-config.yml @@ -24,11 +24,13 @@ limits: max-polygonal-points: default: -1 maximum: 20 + # radius, superpickaxe, brush radius are ignored, use FAWE config limits max-radius: -1 max-super-pickaxe-size: 5 max-brush-radius: 100 butcher-radius: default: -1 + # Ignored, use FAWE config limits maximum: -1 disallowed-blocks: - "minecraft:wheat" diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/scroll/ScrollRange.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/scroll/ScrollRange.java index 405b62b81..db33a526f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/scroll/ScrollRange.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/scroll/ScrollRange.java @@ -13,7 +13,7 @@ public class ScrollRange extends Scroll { @Override public boolean increment(Player player, int amount) { - int max = WorldEdit.getInstance().getConfiguration().maxBrushRadius; + int max = player.getLimit().MAX_BRUSH_RADIUS; int newSize = MathMan.wrap(getTool().getRange() + amount, (int) (getTool().getSize() + 1), max); getTool().setRange(newSize); return true; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/scroll/ScrollSize.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/scroll/ScrollSize.java index cf60639f5..ac34226f2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/scroll/ScrollSize.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/scroll/ScrollSize.java @@ -12,7 +12,7 @@ public class ScrollSize extends Scroll { @Override public boolean increment(Player player, int amount) { - int max = WorldEdit.getInstance().getConfiguration().maxRadius; + int max = player.getLimit().MAX_RADIUS; double newSize = Math.max(0, Math.min(max == -1 ? 4095 : max, getTool().getSize() + amount)); getTool().setSize(newSize); return true; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index 63f37fd6b..33c8c94f0 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -2,6 +2,7 @@ package com.fastasyncworldedit.core.configuration; import com.fastasyncworldedit.core.limit.FaweLimit; import com.fastasyncworldedit.core.limit.PropertyRemap; +import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.world.block.BlockTypesCache; @@ -140,8 +141,22 @@ public class Settings extends Config { ); limit.MAX_FAILS = Math.max(limit.MAX_FAILS, newLimit.MAX_FAILS != -1 ? newLimit.MAX_FAILS : Integer.MAX_VALUE); limit.MAX_ITERATIONS = Math.max( - limit.MAX_ITERATIONS, - newLimit.MAX_ITERATIONS != -1 ? newLimit.MAX_ITERATIONS : Integer.MAX_VALUE + limit.MAX_ITERATIONS, newLimit.MAX_ITERATIONS != -1 ? newLimit.MAX_ITERATIONS : Integer.MAX_VALUE); + limit.MAX_RADIUS = Math.max( + limit.MAX_RADIUS, + newLimit.MAX_RADIUS != -1 ? newLimit.MAX_RADIUS : Integer.MAX_VALUE + ); + limit.MAX_SUPER_PICKAXE_SIZE = Math.max( + limit.MAX_SUPER_PICKAXE_SIZE, + newLimit.MAX_SUPER_PICKAXE_SIZE != -1 ? newLimit.MAX_SUPER_PICKAXE_SIZE : Integer.MAX_VALUE + ); + limit.MAX_BRUSH_RADIUS = Math.max( + limit.MAX_BRUSH_RADIUS, + newLimit.MAX_BRUSH_RADIUS != -1 ? newLimit.MAX_BRUSH_RADIUS : Integer.MAX_VALUE + ); + limit.MAX_BUTCHER_RADIUS = Math.max( + limit.MAX_BUTCHER_RADIUS, + newLimit.MAX_BUTCHER_RADIUS != -1 ? newLimit.MAX_BUTCHER_RADIUS : Integer.MAX_VALUE ); limit.MAX_HISTORY = Math.max( limit.MAX_HISTORY, @@ -352,6 +367,14 @@ public class Settings extends Config { public int MAX_ITERATIONS = 1000; @Comment("Max allowed entities (e.g. cows)") public int MAX_ENTITIES = 1337; + @Comment("Max allowed radius (e.g. for //sphere)") + public int MAX_RADIUS = LocalConfiguration.MAX_RADIUS; + @Comment("Max allowed superpickaxe size") + public int MAX_SUPER_PICKAXE_SIZE = LocalConfiguration.MAX_SUPER_RADIUS; + @Comment("Max allowed brush radius") + public int MAX_BRUSH_RADIUS = LocalConfiguration.MAX_BRUSH_RADIUS; + @Comment("Max allowed butcher radius") + public int MAX_BUTCHER_RADIUS = LocalConfiguration.MAX_BUTCHER_RADIUS; @Comment({ "Blockstates include Banner, Beacon, BrewingStand, Chest, CommandBlock, ", "CreatureSpawner, Dispenser, Dropper, EndGateway, Furnace, Hopper, Jukebox, ", diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/exception/BrushRadiusLimitException.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/exception/BrushRadiusLimitException.java new file mode 100644 index 000000000..838845bd0 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/exception/BrushRadiusLimitException.java @@ -0,0 +1,30 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.fastasyncworldedit.core.exception; + +/** + * Thrown when a maximum radius for a brush is reached. + */ +public class BrushRadiusLimitException extends RadiusLimitException { + + public BrushRadiusLimitException(int maxBrushRadius) { + super(maxBrushRadius); + } +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/exception/RadiusLimitException.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/exception/RadiusLimitException.java new file mode 100644 index 000000000..c7f72af3a --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/exception/RadiusLimitException.java @@ -0,0 +1,41 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.fastasyncworldedit.core.exception; + +import com.sk89q.worldedit.WorldEditException; + +/** + * Thrown when a maximum radius is reached, such as, for example, + * in the case of a sphere command. + */ +public class RadiusLimitException extends WorldEditException { + + private final int maxRadius; + + public RadiusLimitException(int maxRadius) { + this.maxRadius = maxRadius; + } + + public int getMaxRadius() { + return maxRadius; + } + //FAWE end + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java index e02e3abc9..5ecc89d44 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java @@ -18,6 +18,10 @@ public class FaweLimit { public int SCHEM_FILE_SIZE_LIMIT = 0; public int SCHEM_FILE_NUM_LIMIT = 0; public int MAX_EXPRESSION_MS = 0; + public int MAX_RADIUS = 0; + public int MAX_SUPER_PICKAXE_SIZE = 0; + public int MAX_BRUSH_RADIUS = 0; + public int MAX_BUTCHER_RADIUS = 0; public int INVENTORY_MODE = Integer.MAX_VALUE; public int SPEED_REDUCTION = Integer.MAX_VALUE; public boolean FAST_PLACEMENT = false; @@ -123,6 +127,10 @@ public class FaweLimit { MAX.UNIVERSAL_DISALLOWED_BLOCKS = false; MAX.DISALLOWED_BLOCKS = Collections.emptySet(); MAX.REMAP_PROPERTIES = Collections.emptySet(); + MAX.MAX_RADIUS = Integer.MAX_VALUE; + MAX.MAX_SUPER_PICKAXE_SIZE = Integer.MAX_VALUE; + MAX.MAX_BRUSH_RADIUS = Integer.MAX_VALUE; + MAX.MAX_BUTCHER_RADIUS = Integer.MAX_VALUE; } public boolean MAX_CHANGES() { @@ -250,7 +258,12 @@ public class FaweLimit { && (STRIP_NBT == null || STRIP_NBT.isEmpty()) // && !UNIVERSAL_DISALLOWED_BLOCKS --> do not include this, it effectively has no relevance && (DISALLOWED_BLOCKS == null || DISALLOWED_BLOCKS.isEmpty()) - && (REMAP_PROPERTIES == null || REMAP_PROPERTIES.isEmpty()); + && (REMAP_PROPERTIES == null || REMAP_PROPERTIES.isEmpty()) + && MAX_RADIUS == Integer.MAX_VALUE + && MAX_SUPER_PICKAXE_SIZE == Integer.MAX_VALUE + && MAX_BRUSH_RADIUS == Integer.MAX_VALUE + && MAX_BUTCHER_RADIUS == Integer.MAX_VALUE; + } public void set(FaweLimit limit) { @@ -273,6 +286,10 @@ public class FaweLimit { UNIVERSAL_DISALLOWED_BLOCKS = limit.UNIVERSAL_DISALLOWED_BLOCKS; DISALLOWED_BLOCKS = limit.DISALLOWED_BLOCKS; REMAP_PROPERTIES = limit.REMAP_PROPERTIES; + MAX_RADIUS = limit.MAX_RADIUS; + MAX_SUPER_PICKAXE_SIZE = limit.MAX_SUPER_PICKAXE_SIZE; + MAX_BRUSH_RADIUS = limit.MAX_BRUSH_RADIUS; + MAX_BUTCHER_RADIUS = limit.MAX_BUTCHER_RADIUS; } public FaweLimit copy() { @@ -296,6 +313,10 @@ public class FaweLimit { limit.UNIVERSAL_DISALLOWED_BLOCKS = UNIVERSAL_DISALLOWED_BLOCKS; limit.DISALLOWED_BLOCKS = DISALLOWED_BLOCKS; limit.REMAP_PROPERTIES = REMAP_PROPERTIES; + limit.MAX_RADIUS = MAX_RADIUS; + limit.MAX_SUPER_PICKAXE_SIZE = MAX_SUPER_PICKAXE_SIZE; + limit.MAX_BRUSH_RADIUS = MAX_BRUSH_RADIUS; + limit.MAX_BUTCHER_RADIUS = MAX_BUTCHER_RADIUS; return limit; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java index 57ec6f186..7e2ba4549 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java @@ -52,12 +52,26 @@ import java.util.Set; public abstract class LocalConfiguration { private static final Logger LOGGER = LogManagerCompat.getLogger(); + //FAWE start - inelegant but required to transfer to FAWE limits as defaults + public static int MAX_RADIUS; + public static int MAX_SUPER_RADIUS; + public static int MAX_BRUSH_RADIUS; + public static int MAX_BUTCHER_RADIUS; + //FAWE end public boolean profile = false; public boolean traceUnflushedSessions = true; public Set disallowedBlocks = new HashSet<>(); protected BlockMask disallowedBlocksMask; + /** + * @deprecated Use actor's limit {@link com.fastasyncworldedit.core.limit.FaweLimit#MAX_CHANGES} + */ + @Deprecated public int defaultChangeLimit = -1; + /** + * @deprecated Use actor's limit {@link com.fastasyncworldedit.core.limit.FaweLimit#MAX_CHANGES} + */ + @Deprecated public int maxChangeLimit = -1; public int defaultVerticalHeight = 256; public int defaultMaxPolygonalPoints = -1; @@ -68,8 +82,20 @@ public abstract class LocalConfiguration { public boolean snapshotsConfigured = false; public SnapshotRepository snapshotRepo = null; public SnapshotDatabase snapshotDatabase = null; + /** + * @deprecated Use actor's limit {@link com.fastasyncworldedit.core.limit.FaweLimit#MAX_RADIUS} + */ + @Deprecated public int maxRadius = -1; + /** + * @deprecated Use actor's limit {@link com.fastasyncworldedit.core.limit.FaweLimit#MAX_SUPER_PICKAXE_SIZE} + */ + @Deprecated public int maxSuperPickaxeSize = 5; + /** + * @deprecated Use actor's limit {@link com.fastasyncworldedit.core.limit.FaweLimit#MAX_BRUSH_RADIUS} + */ + @Deprecated public int maxBrushRadius = 6; public boolean logCommands = false; public String logFile = ""; @@ -92,6 +118,10 @@ public abstract class LocalConfiguration { public String scriptsDir = "craftscripts"; public boolean showHelpInfo = true; // unused public int butcherDefaultRadius = -1; + /** + * @deprecated Use actor's limit {@link com.fastasyncworldedit.core.limit.FaweLimit#MAX_BUTCHER_RADIUS} + */ + @Deprecated public int butcherMaxRadius = -1; public boolean allowSymlinks = false; public boolean serverSideCUI = true; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/MaxBrushRadiusException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/MaxBrushRadiusException.java index 76a640c66..cb1371451 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/MaxBrushRadiusException.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/MaxBrushRadiusException.java @@ -19,9 +19,24 @@ package com.sk89q.worldedit; +import com.fastasyncworldedit.core.exception.BrushRadiusLimitException; +import com.fastasyncworldedit.core.exception.RadiusLimitException; + /** * Thrown when a maximum radius for a brush is reached. + * + * @deprecated Use {@link RadiusLimitException} */ +@Deprecated public class MaxBrushRadiusException extends MaxRadiusException { + //FAWE start + + /** + * @deprecated Use {@link BrushRadiusLimitException} + */ + @Deprecated + public MaxBrushRadiusException() { + } + //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/MaxRadiusException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/MaxRadiusException.java index 6641c063c..1e5da912f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/MaxRadiusException.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/MaxRadiusException.java @@ -19,10 +19,24 @@ package com.sk89q.worldedit; +import com.fastasyncworldedit.core.exception.RadiusLimitException; + /** * Thrown when a maximum radius is reached, such as, for example, * in the case of a sphere command. + * + * @deprecated Use {@link RadiusLimitException} */ +@Deprecated public class MaxRadiusException extends WorldEditException { + //FAWE start + /** + * @deprecated Use {@link RadiusLimitException} + */ + @Deprecated + public MaxRadiusException() { + } + //FAWE end + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java index 2c62e08ec..be4c9af8c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -20,6 +20,8 @@ package com.sk89q.worldedit; import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.exception.BrushRadiusLimitException; +import com.fastasyncworldedit.core.exception.RadiusLimitException; import com.fastasyncworldedit.core.extension.factory.TransformFactory; import com.fastasyncworldedit.core.extent.ResettableExtent; import com.google.common.base.Throwables; @@ -437,7 +439,9 @@ public final class WorldEdit { * * @param radius the radius * @throws MaxRadiusException if the radius is bigger than the configured radius + * @deprecated Use {@link WorldEdit#checkMaxRadius(double, Actor)} */ + @Deprecated public void checkMaxRadius(double radius) throws MaxRadiusException { if (getConfiguration().maxRadius > 0 && radius > getConfiguration().maxRadius) { throw new MaxRadiusException(); @@ -449,7 +453,9 @@ public final class WorldEdit { * * @param radius the radius * @throws MaxBrushRadiusException if the radius is bigger than the configured radius + * @deprecated Use {@link WorldEdit#checkMaxBrushRadius(double, Actor)} */ + @Deprecated public void checkMaxBrushRadius(double radius) throws MaxBrushRadiusException { if (getConfiguration().maxBrushRadius > 0 && radius > getConfiguration().maxBrushRadius) { throw new MaxBrushRadiusException(); @@ -457,6 +463,10 @@ public final class WorldEdit { } //FAWE start + /** + * @deprecated Use {@link WorldEdit#checkMaxBrushRadius(Expression, Actor)} + */ + @Deprecated(forRemoval = true, since = "TODO") public void checkMaxBrushRadius(Expression radius) throws MaxBrushRadiusException { double val = radius.evaluate(); checkArgument(val >= 0, "Radius must be a positive number."); @@ -466,6 +476,53 @@ public final class WorldEdit { } } } + + /** + * Check the given radius against the give actor's limit. + * + * @param radius Radius to check + * @param actor Actor to check for + * @throws MaxRadiusException If given radius larger than allowed + * @since TODO + */ + public void checkMaxRadius(double radius, Actor actor) { + int max = actor.getLimit().MAX_RADIUS; + if (max > 0 && radius > max) { + throw new RadiusLimitException(max); + } + } + + /** + * Check the given radius against the give actor's limit. + * + * @param radius Radius to check + * @param actor Actor to check for + * @throws MaxRadiusException If given radius larger than allowed + * @since TODO + */ + public void checkMaxBrushRadius(double radius, Actor actor) { + int max = actor.getLimit().MAX_BRUSH_RADIUS; + if (max > 0 && radius > max) { + throw new RadiusLimitException(max); + } + } + + /** + * Check the given radius against the give actor's limit. + * + * @param expression Radius to check + * @param actor Actor to check for + * @throws BrushRadiusLimitException If given radius larger than allowed + * @since TODO + */ + public void checkMaxBrushRadius(Expression expression, Actor actor) { + double radius = expression.evaluate(); + checkArgument(radius >= 0, "Radius must be a positive number."); + int max = actor.getLimit().MAX_BRUSH_RADIUS; + if (max > 0 && radius > max) { + throw new BrushRadiusLimitException(max); + } + } //FAWE end /** 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 76cb60c64..bdd6a4ed4 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 @@ -186,7 +186,10 @@ public class BrushCommands { @ArgFlag(name = 'm', desc = "Mask to limit blocks being considered", def = "") Mask mask ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); checkCommandArgument(minFreqDiff >= 0 && minFreqDiff <= 26, "minFreqDiff not in range 0 <= value <= 26"); if (mask != null && !(mask instanceof CachedMask)) { mask = new CachedMask(mask, false); @@ -212,7 +215,10 @@ public class BrushCommands { @Arg(desc = "fillRec", def = "1") int fillRec ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); set(context, new ErodeBrush(erodefaces, erodeRec, fillFaces, fillRec), "worldedit.brush.erode").setSize(radius); } @@ -234,7 +240,10 @@ public class BrushCommands { @Arg(desc = "fillRec", def = "1") int fillRec ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); set(context, new RaiseBrush(erodefaces, erodeRec, fillFaces, fillRec), "worldedit.brush.pull").setSize(radius); } @@ -252,7 +261,10 @@ public class BrushCommands { @Arg(name = "filled", desc = "Whether the circle should be filled", def = "false") boolean filled ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); set(context, new CircleBrush(filled), "worldedit.brush.sphere").setSize(radius).setFill(fill); } @@ -276,7 +288,10 @@ public class BrushCommands { @Switch(name = 'd', desc = "Apply in depth first order") boolean depthFirst ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); set(context, new RecurseBrush(depthFirst), "worldedit.brush.recursive").setSize(radius).setFill(fill) .setMask(new IdMask(editSession)); } @@ -299,7 +314,10 @@ public class BrushCommands { @Switch(name = 'f', desc = "Create a flat line") boolean flat ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); set(context, new LineBrush(shell, select, flat), "worldedit.brush.line").setSize(radius).setFill(fill); } @@ -326,7 +344,10 @@ public class BrushCommands { Expression radius ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); player.print(Caption.of("fawe.worldedit.brush.brush.spline", (radius))); set(context, new SplineBrush(player), "worldedit.brush.spline").setSize(radius).setFill(fill); } @@ -379,7 +400,10 @@ public class BrushCommands { @Switch(name = 'd', desc = "sags the catenary toward the facing direction") boolean facingDirection ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); set(context, new CatenaryBrush(shell, select, facingDirection, lengthFactor), "worldedit.brush.spline") .setSize(radius).setFill(fill); } @@ -411,7 +435,10 @@ public class BrushCommands { double quality ) throws WorldEditException { player.print(Caption.of("fawe.worldedit.brush.brush.spline", (radius))); - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); set(context, new SurfaceSpline(tension, bias, continuity, quality), "surfacespline").setSize(radius) .setFill(fill); } @@ -436,9 +463,11 @@ public class BrushCommands { double amplitude ) throws WorldEditException { double max = MathMan.max(radius.getX(), radius.getY(), radius.getZ()); - worldEdit.checkMaxBrushRadius(max); - Brush brush = - new BlobBrush(radius.divide(max), frequency / 100, amplitude / 100, sphericity / 100); + worldEdit.checkMaxBrushRadius( + max, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); + Brush brush = new BlobBrush(radius.divide(max), frequency / 100, amplitude / 100, sphericity / 100); set(context, brush, "worldedit.brush.rock").setSize(max).setFill(fill); } @@ -459,7 +488,10 @@ public class BrushCommands { @Arg(desc = "Lines", def = "10") int count ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); set(context, new ShatterBrush(count), "worldedit.brush.shatter").setSize(radius).setFill(fill) .setMask(new ExistingBlockMask(editSession)); } @@ -490,7 +522,10 @@ public class BrushCommands { boolean randomRotate ) throws WorldEditException, FileNotFoundException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); InputStream stream = getHeightmapStream(image); HeightBrush brush; int minY = player.getWorld().getMinY(); @@ -526,7 +561,10 @@ public class BrushCommands { URL url = new URL(imageURL); MainUtil.checkImageHost(url.toURI()); BufferedImage image = MainUtil.readImage(url); - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); if (yscale != 1) { ImageUtil.scaleAlpha(image, yscale); alpha = true; @@ -553,7 +591,10 @@ public class BrushCommands { @Arg(desc = "Expression", def = "5") Expression radius ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); set(context, new SurfaceSphereBrush(), "worldedit.brush.surface").setFill(fill).setSize(radius); } @@ -578,7 +619,10 @@ public class BrushCommands { @Switch(name = 'o', desc = "Overlay the block") boolean overlay ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); Brush brush; if (overlay) { brush = new ScatterOverlayBrush((int) points, (int) distance); @@ -612,7 +656,10 @@ public class BrushCommands { @Switch(name = 'r', desc = "Apply random rotation") boolean rotate ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); try { MultiClipboardHolder clipboards = ClipboardFormats.loadAllFromInput(player, clipboardStr, null, true); @@ -651,7 +698,10 @@ public class BrushCommands { List patternLayers ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); set(context, new LayerBrush(patternLayers.toArray(new Pattern[0])), "worldedit.brush.layer").setSize(radius); } @@ -678,7 +728,10 @@ public class BrushCommands { @Arg(desc = "boolean", def = "true") boolean solid ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); set(context, new SplatterBrush((int) points, (int) recursion, solid), "worldedit.brush.splatter").setSize(radius) .setFill(fill); } @@ -711,7 +764,10 @@ public class BrushCommands { boolean print ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); set( context, new ScatterCommand((int) points, (int) distance, StringMan.join(commandStr, " "), print), @@ -838,7 +894,10 @@ public class BrushCommands { InjectedValueAccess context ) throws WorldEditException, FileNotFoundException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); InputStream stream = getHeightmapStream(image); HeightBrush brush; int minY = player.getWorld().getMinY(); @@ -908,7 +967,10 @@ public class BrushCommands { @Switch(name = 'a', desc = "Apply auto view based rotation on paste") boolean autoRotate ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); player.print(Caption.of("fawe.worldedit.brush.brush.copy", (radius))); set(context, new CopyPastaBrush(player, session, randomRotate, autoRotate), "worldedit.brush.copy").setSize(radius); @@ -933,7 +995,10 @@ public class BrushCommands { @Switch(name = 'p', desc = "Show any printed output") boolean print ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); String cmd = StringMan.join(input, " "); set(context, new CommandBrush(cmd, print), "worldedit.brush.command").setSize(radius); } @@ -1042,7 +1107,7 @@ public class BrushCommands { String permission ) throws WorldEditException { - WorldEdit.getInstance().checkMaxBrushRadius(radius); + WorldEdit.getInstance().checkMaxBrushRadius(radius, player); BrushTool tool = session.getBrushTool(player); tool.setSize(radius); tool.setFill(null); @@ -1197,7 +1262,10 @@ public class BrushCommands { @Switch(name = 'f', desc = "Create falling spheres instead") boolean falling ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); Brush brush; if (hollow) { brush = new HollowSphereBrush(); @@ -1244,8 +1312,14 @@ public class BrushCommands { @Switch(name = 'h', desc = "Create hollow cylinders instead") boolean hollow ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); - worldEdit.checkMaxBrushRadius(height); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); + worldEdit.checkMaxBrushRadius( + height, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); BrushSettings settings; if (hollow) { @@ -1293,9 +1367,18 @@ public class BrushCommands { BlockVector3 size = clipboard.getDimensions(); - worldEdit.checkMaxBrushRadius(size.getBlockX() / 2D - 1); - worldEdit.checkMaxBrushRadius(size.getBlockY() / 2D - 1); - worldEdit.checkMaxBrushRadius(size.getBlockZ() / 2D - 1); + worldEdit.checkMaxBrushRadius( + size.getBlockX() / 2D - 1, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); + worldEdit.checkMaxBrushRadius( + size.getBlockY() / 2D - 1, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); + worldEdit.checkMaxBrushRadius( + size.getBlockZ() / 2D - 1, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); set( context, @@ -1324,7 +1407,10 @@ public class BrushCommands { Mask mask, InjectedValueAccess context ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); //FAWE start FaweLimit limit = Settings.settings().getLimit(player); @@ -1359,7 +1445,10 @@ public class BrushCommands { @ArgFlag(name = 'm', desc = "The mask of blocks to use for the heightmap") Mask mask, InjectedValueAccess context ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); //FAWE start FaweLimit limit = Settings.settings().getLimit(player); @@ -1386,7 +1475,10 @@ public class BrushCommands { @Arg(desc = "The radius to extinguish", def = "5") Expression radius ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); set(context, new SphereBrush(), "worldedit.brush.ex").setSize(radius).setFill(BlockTypes.AIR.getDefaultState()) .setMask(new SingleBlockTypeMask(editSession, BlockTypes.FIRE)); @@ -1405,7 +1497,10 @@ public class BrushCommands { @Switch(name = 'h', desc = "Affect blocks starting at max Y, rather than the target location Y + radius") boolean fromMaxY ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); set(context, new GravityBrush(fromMaxY), "worldedit.brush.gravity").setSize(radius); } @@ -1439,7 +1534,10 @@ public class BrushCommands { @Switch(name = 'w', desc = "Also kill water mobs") boolean killWater, InjectedValueAccess context ) throws WorldEditException { - worldEdit.checkMaxBrushRadius(radius); + worldEdit.checkMaxBrushRadius( + radius, + context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) + ); CreatureButcher flags = new CreatureButcher(player); flags.or( @@ -1508,7 +1606,7 @@ public class BrushCommands { RegionFactory shape, String permission ) throws WorldEditException { - WorldEdit.getInstance().checkMaxBrushRadius(radius); + WorldEdit.getInstance().checkMaxBrushRadius(radius, player); BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); tool.setSize(radius); tool.setFill(null); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index d3d456965..90b59cb52 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 @@ -130,9 +130,9 @@ public class GenerationCommands { return 0; } } - worldEdit.checkMaxRadius(radiusX); - worldEdit.checkMaxRadius(radiusZ); - worldEdit.checkMaxRadius(height); + worldEdit.checkMaxRadius(radiusX, actor); + worldEdit.checkMaxRadius(radiusZ, actor); + worldEdit.checkMaxRadius(height, actor); if (thickness > radiusX || thickness > radiusZ) { actor.print(Caption.of("worldedit.hcyl.thickness-too-large")); @@ -178,9 +178,9 @@ public class GenerationCommands { } } - worldEdit.checkMaxRadius(radiusX); - worldEdit.checkMaxRadius(radiusZ); - worldEdit.checkMaxRadius(height); + worldEdit.checkMaxRadius(radiusX, actor); + worldEdit.checkMaxRadius(radiusZ, actor); + worldEdit.checkMaxRadius(height, actor); BlockVector3 pos = session.getPlacementPosition(actor); int affected = editSession.makeCylinder(pos, pattern, radiusX, radiusZ, height, !hollow); @@ -224,9 +224,9 @@ public class GenerationCommands { } } - worldEdit.checkMaxRadius(radiusX); - worldEdit.checkMaxRadius(radiusZ); - worldEdit.checkMaxRadius(height); + worldEdit.checkMaxRadius(radiusX, actor); + worldEdit.checkMaxRadius(radiusZ, actor); + worldEdit.checkMaxRadius(height, actor); BlockVector3 pos = session.getPlacementPosition(actor); int affected = editSession.makeCone(pos, pattern, radiusX, radiusZ, height, !hollow, thickness); @@ -290,9 +290,9 @@ public class GenerationCommands { } } - worldEdit.checkMaxRadius(radiusX); - worldEdit.checkMaxRadius(radiusY); - worldEdit.checkMaxRadius(radiusZ); + worldEdit.checkMaxRadius(radiusX, actor); + worldEdit.checkMaxRadius(radiusY, actor); + worldEdit.checkMaxRadius(radiusZ, actor); BlockVector3 pos = session.getPlacementPosition(actor); if (raised) { pos = pos.add(0, (int) radiusY, 0); @@ -323,7 +323,7 @@ public class GenerationCommands { double density ) throws WorldEditException { checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100"); - worldEdit.checkMaxRadius(size); + worldEdit.checkMaxRadius(size, actor); density /= 100; int affected = editSession.makeForest(session.getPlacementPosition(actor), size, density, type); actor.print(Caption.of("worldedit.forestgen.created", TextComponent.of(affected))); @@ -345,7 +345,7 @@ public class GenerationCommands { double density ) throws WorldEditException { checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100"); - worldEdit.checkMaxRadius(size); + worldEdit.checkMaxRadius(size, actor); int affected = editSession.makePumpkinPatches(session.getPlacementPosition(actor), size, density); actor.print(Caption.of("worldedit.pumpkins.created", TextComponent.of(affected))); return affected; @@ -382,7 +382,7 @@ public class GenerationCommands { @Switch(name = 'h', desc = "Make a hollow pyramid") boolean hollow ) throws WorldEditException { - worldEdit.checkMaxRadius(size); + worldEdit.checkMaxRadius(size, actor); BlockVector3 pos = session.getPlacementPosition(actor); int affected = editSession.makePyramid(pos, pattern, size, !hollow); if (actor instanceof Player && Settings.settings().GENERAL.UNSTUCK_ON_GENERATE) { @@ -736,7 +736,7 @@ public class GenerationCommands { double amplitude ) throws WorldEditException { double max = MathMan.max(radius.getX(), radius.getY(), radius.getZ()); - worldEdit.checkMaxRadius(max); + worldEdit.checkMaxRadius(max, actor); BlockVector3 pos = session.getPlacementPosition(actor); int affected = editSession.makeBlob( pos, diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java index cb24daec5..fdd86498f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java @@ -66,10 +66,11 @@ public class SuperPickaxeCommands { int range ) throws WorldEditException { - LocalConfiguration config = we.getConfiguration(); - - if (range > config.maxSuperPickaxeSize) { - player.print(Caption.of("worldedit.tool.superpickaxe.max-range", TextComponent.of(config.maxSuperPickaxeSize))); + if (range > player.getLimit().MAX_SUPER_PICKAXE_SIZE) { + player.print(Caption.of( + "worldedit.tool.superpickaxe.max-range", + TextComponent.of(player.getLimit().MAX_SUPER_PICKAXE_SIZE) + )); return; } session.setSuperPickaxe(new AreaPickaxe(range)); @@ -89,10 +90,11 @@ public class SuperPickaxeCommands { double range ) throws WorldEditException { - LocalConfiguration config = we.getConfiguration(); - - if (range > config.maxSuperPickaxeSize) { - player.print(Caption.of("worldedit.tool.superpickaxe.max-range", TextComponent.of(config.maxSuperPickaxeSize))); + if (range > player.getLimit().MAX_SUPER_PICKAXE_SIZE) { + player.print(Caption.of( + "worldedit.tool.superpickaxe.max-range", + TextComponent.of(player.getLimit().MAX_SUPER_PICKAXE_SIZE) + )); return; } 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 8395b2e2d..95499372c 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 @@ -297,10 +297,11 @@ public class ToolCommands { int range ) throws WorldEditException { - LocalConfiguration config = we.getConfiguration(); - - if (range > config.maxSuperPickaxeSize) { - player.print(Caption.of("worldedit.tool.superpickaxe.max-range", TextComponent.of(config.maxSuperPickaxeSize))); + if (range > player.getLimit().MAX_SUPER_PICKAXE_SIZE) { + player.print(Caption.of( + "worldedit.tool.superpickaxe.max-range", + TextComponent.of(player.getLimit().MAX_SUPER_PICKAXE_SIZE) + )); return; } setTool(player, session, new FloodFillTool(range, pattern), "worldedit.tool.floodfill.equip"); 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 0694b2af3..48fb76318 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 @@ -154,7 +154,7 @@ public class ToolUtilCommands { @Arg(desc = "The size of the brush") int size ) throws WorldEditException { - we.checkMaxBrushRadius(size); + we.checkMaxBrushRadius(size, player); session.getBrushTool(player).setSize(size); player.print(Caption.of("worldedit.tool.size.set")); 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 aca13bc46..a336f4b12 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 @@ -246,8 +246,9 @@ public class UtilityCommands { double radius = radiusExp.evaluate(); //FAWE end radius = Math.max(1, radius); - we.checkMaxRadius(radius); + we.checkMaxRadius(radius, actor); depth = Math.max(1, depth); + we.checkMaxRadius(depth, actor); BlockVector3 pos = session.getPlacementPosition(actor); int affected = editSession.fillDirection(pos, pattern, radius, depth, direction); @@ -333,9 +334,9 @@ public class UtilityCommands { double radius = radiusExp.evaluate(); //FAWE end radius = Math.max(1, radius); - we.checkMaxRadius(radius); + we.checkMaxRadius(radius, actor); depth = depth == null ? Integer.MAX_VALUE : Math.max(1, depth); - we.checkMaxRadius(radius); + we.checkMaxRadius(radius, actor); BlockVector3 pos = session.getPlacementPosition(actor); int affected = editSession.fillXZ(pos, pattern, radius, depth, true); @@ -364,7 +365,7 @@ public class UtilityCommands { //FAWE end double radius = radiusExp.evaluate(); radius = Math.max(0, radius); - we.checkMaxRadius(radius); + we.checkMaxRadius(radius, actor); int affected = editSession.drainArea(session.getPlacementPosition(actor), radius, waterlogged, plants); actor.print(Caption.of("worldedit.drain.drained", TextComponent.of(affected))); return affected; @@ -383,7 +384,7 @@ public class UtilityCommands { double radius ) throws WorldEditException { radius = Math.max(0, radius); - we.checkMaxRadius(radius); + we.checkMaxRadius(radius, actor); int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.LAVA); actor.print(Caption.of("worldedit.fixlava.fixed", TextComponent.of(affected))); return affected; @@ -402,7 +403,7 @@ public class UtilityCommands { double radius ) throws WorldEditException { radius = Math.max(0, radius); - we.checkMaxRadius(radius); + we.checkMaxRadius(radius, actor); int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.WATER); actor.print(Caption.of("worldedit.fixwater.fixed", TextComponent.of(affected))); return affected; @@ -423,7 +424,7 @@ public class UtilityCommands { Integer height ) throws WorldEditException { size = Math.max(1, size); - we.checkMaxRadius(size); + we.checkMaxRadius(size, actor); height = height != null ? Math.min((world.getMaxY() - world.getMinY() + 1), height + 1) @@ -448,7 +449,7 @@ public class UtilityCommands { Integer height ) throws WorldEditException { size = Math.max(1, size); - we.checkMaxRadius(size); + we.checkMaxRadius(size, actor); height = height != null ? Math.min((world.getMaxY() - world.getMinY() + 1), height + 1) @@ -476,7 +477,7 @@ public class UtilityCommands { new MaskTraverser(mask).setNewExtent(editSession); //FAWE end radius = Math.max(1, radius); - we.checkMaxRadius(radius); + we.checkMaxRadius(radius, actor); int affected = editSession.removeNear(session.getPlacementPosition(actor), mask, radius); actor.print(Caption.of("worldedit.removenear.removed", TextComponent.of(affected))); @@ -503,7 +504,7 @@ public class UtilityCommands { new MaskTraverser(from).setNewExtent(editSession); //FAWE end radius = Math.max(1, radius); - we.checkMaxRadius(radius); + we.checkMaxRadius(radius, actor); BlockVector3 base = session.getPlacementPosition(actor); BlockVector3 min = base.subtract(radius, radius, radius); @@ -542,7 +543,7 @@ public class UtilityCommands { ) throws WorldEditException { size = Math.max(1, size); height = Math.max(1, height); - we.checkMaxRadius(size); + we.checkMaxRadius(size, actor); BlockVector3 position = session.getPlacementPosition(actor); @@ -579,7 +580,7 @@ public class UtilityCommands { ) throws WorldEditException { size = Math.max(1, size); height = Math.max(1, height); - we.checkMaxRadius(size); + we.checkMaxRadius(size, actor); int affected = editSession.thaw(session.getPlacementPosition(actor), size, height); actor.print(Caption.of( @@ -610,7 +611,7 @@ public class UtilityCommands { ) throws WorldEditException { size = Math.max(1, size); height = Math.max(1, height); - we.checkMaxRadius(size); + we.checkMaxRadius(size, actor); final boolean onlyNormalDirt = !convertCoarse; final int affected = editSession.green( @@ -635,11 +636,9 @@ public class UtilityCommands { Integer radius ) throws WorldEditException { - LocalConfiguration config = we.getConfiguration(); - - int defaultRadius = config.maxRadius != -1 ? Math.min(40, config.maxRadius) : 40; + int defaultRadius = actor.getLimit().MAX_RADIUS != -1 ? Math.min(40, actor.getLimit().MAX_RADIUS) : 40; int size = radius != null ? Math.max(1, radius) : defaultRadius; - we.checkMaxRadius(size); + we.checkMaxRadius(size, actor); Mask mask = new BlockTypeMask(editSession, BlockTypes.FIRE); int affected = editSession.removeNear(session.getPlacementPosition(actor), mask, size); @@ -685,12 +684,12 @@ public class UtilityCommands { actor.print(Caption.of("worldedit.butcher.explain-all")); return 0; } else if (radius == -1) { - if (config.butcherMaxRadius != -1) { - radius = config.butcherMaxRadius; + if (actor.getLimit().MAX_BUTCHER_RADIUS != -1) { + radius = actor.getLimit().MAX_BUTCHER_RADIUS; } } - if (config.butcherMaxRadius != -1) { - radius = Math.min(radius, config.butcherMaxRadius); + if (actor.getLimit().MAX_BUTCHER_RADIUS != -1) { + radius = Math.min(radius, actor.getLimit().MAX_BUTCHER_RADIUS); } CreatureButcher flags = new CreatureButcher(actor); 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 d6c44fa66..c4d45d683 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 @@ -477,7 +477,7 @@ public class BrushTool try { new PatternTraverser(current).reset(editSession); double size = current.getSize(); - WorldEdit.getInstance().checkMaxBrushRadius(size); + WorldEdit.getInstance().checkMaxBrushRadius(size, player); brush.build(editSession, target.toBlockPoint(), current.getMaterial(), size); } catch (MaxChangedBlocksException e) { player.print(Caption.of("worldedit.tool.max-block-changes")); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/Confirm.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/Confirm.java index a2854a8c7..37ea4abeb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/Confirm.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/Confirm.java @@ -75,7 +75,7 @@ public @interface Confirm { if (checkExisting(context)) { return true; } - int max = WorldEdit.getInstance().getConfiguration().maxRadius; + int max = actor.getLimit().MAX_RADIUS; if (max != -1 && value > max) { actor.print(Caption.of("fawe.cancel.reason.confirm.radius", value, max, getArgs(context) 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 a0c5eb328..b07f3f61d 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 @@ -20,6 +20,8 @@ package com.sk89q.worldedit.internal.command.exception; import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.exception.BrushRadiusLimitException; +import com.fastasyncworldedit.core.exception.RadiusLimitException; import com.fastasyncworldedit.core.internal.exception.FaweException; import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.DisallowedItemException; @@ -134,6 +136,18 @@ public class WorldEditExceptionConverter extends ExceptionConverterHelper { ); } + //FAWE start + @ExceptionMatch + public void convert(BrushRadiusLimitException e) throws CommandException { + throw newCommandException(Caption.of("fawe.error.limit.max-brush-radius", TextComponent.of(e.getMaxRadius())), e); + } + + @ExceptionMatch + public void convert(RadiusLimitException e) throws CommandException { + throw newCommandException(Caption.of("fawe.error.limit.max-radius", TextComponent.of(e.getMaxRadius())), e); + } + //FAWE end + @ExceptionMatch public void convert(UnknownDirectionException e) throws CommandException { throw newCommandException(e.getRichMessage(), e); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java index f350af03f..3804be8d3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java @@ -136,6 +136,14 @@ public class PropertiesConfiguration extends LocalConfiguration { scriptsDir = getString("craftscript-dir", scriptsDir); butcherDefaultRadius = getInt("butcher-default-radius", butcherDefaultRadius); butcherMaxRadius = getInt("butcher-max-radius", butcherMaxRadius); + + //FAWE start + MAX_RADIUS = maxRadius; + MAX_BRUSH_RADIUS = maxBrushRadius; + MAX_SUPER_RADIUS = maxSuperPickaxeSize; + MAX_BUTCHER_RADIUS = butcherMaxRadius; + //FAWE end + allowSymlinks = getBool("allow-symbolic-links", allowSymlinks); serverSideCUI = getBool("server-side-cui", serverSideCUI); extendedYLimit = getBool("extended-y-limit", extendedYLimit); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java index 1a8b0667c..7b0cbf4b8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java @@ -95,6 +95,13 @@ public class YAMLConfiguration extends LocalConfiguration { butcherDefaultRadius = Math.max(-1, config.getInt("limits.butcher-radius.default", butcherDefaultRadius)); butcherMaxRadius = Math.max(-1, config.getInt("limits.butcher-radius.maximum", butcherMaxRadius)); + //FAWE start + MAX_RADIUS = maxRadius; + MAX_BRUSH_RADIUS = maxBrushRadius; + MAX_SUPER_RADIUS = maxSuperPickaxeSize; + MAX_BUTCHER_RADIUS = butcherMaxRadius; + //FAWE end + disallowedBlocks = config.getStringList("limits.disallowed-blocks", Lists.newArrayList(getDefaultDisallowedBlocks())) .stream() .map(s -> s.contains(":") ? s.toLowerCase(Locale.ROOT) : ("minecraft:" + s).toLowerCase(Locale.ROOT)) diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index 208de9027..c343dd623 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -137,6 +137,8 @@ "fawe.error.limit.disallowed-property": "Your limit disallows use of property '{0}'", "fawe.error.region-mask-invalid": "Invalid region mask: {0}", "fawe.error.occurred-continuing": "Ignorable error occurred during edit: {0}", + "fawe.error.limit.max-brush-radius": "Maximum brush radius in limit: {0}", + "fawe.error.limit.max-radius": "Maximum radius in limit: {0}", "fawe.cancel.count": "Cancelled {0} edits.", "fawe.cancel.reason.confirm": "Use //confirm to execute {0}", "fawe.cancel.reason.confirm.region": "Your selection is large ({0} -> {1}, containing {3} blocks). Use //confirm to execute {2}", From c77d34156b5f5b460691c74a5573a8a0ba1d7996 Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Sat, 25 May 2024 13:36:37 +0200 Subject: [PATCH 253/466] Fix compatibility with WorldGuard (#2743) * Make the Vector classes into Records (#2477) * Make the Vector classes into Records * Drop custom equals and hashCode methods in Vector/BlockVector classes (cherry picked from commit 0df2b6af4c1ce18b77eedd5c62eeb45011512103) Signed-off-by: Pierre Maurice Schwang * chore: cleanup cherry-pick issues, migrate to new methods * chore: add since attributes to deprecated tags, use MathMan instead of Math std lib for rounding ints * chore: mark custom hashCode + equals implementations diffing from upstream --------- Co-authored-by: Maddy Miller --- .../adapters/adapter-1_20_5/build.gradle.kts | 2 +- .../filter/block/AbstractFilterBlock.java | 20 +- .../extent/filter/block/ArrayFilterBlock.java | 10 +- .../extent/filter/block/CharFilterBlock.java | 16 +- .../core/extent/filter/block/FilterBlock.java | 32 +-- .../filter/block/SingleFilterBlock.java | 6 +- .../core/math/DelegateBlockVector3.java | 27 +- .../core/math/MutableBlockVector3.java | 22 +- .../core/math/MutableVector3.java | 14 +- .../core/math/OffsetBlockVector3.java | 12 +- .../core/math/Vector3Impl.java | 8 +- .../sk89q/worldedit/math/BlockVector2.java | 35 ++- .../sk89q/worldedit/math/BlockVector3.java | 253 ++++++++++------- .../sk89q/worldedit/math/BlockVector3Imp.java | 12 +- .../com/sk89q/worldedit/math/Vector2.java | 59 ++-- .../com/sk89q/worldedit/math/Vector3.java | 266 +++++++++++------- .../com/sk89q/worldedit/util/Location.java | 14 +- 17 files changed, 454 insertions(+), 354 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts index a0ee57dc2..80c044f91 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/ - the().paperDevBundle("1.20.6-R0.1-20240520.005421-60") + the().paperDevBundle("1.20.6-R0.1-20240523.202134-70") compileOnly(libs.paperlib) } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/AbstractFilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/AbstractFilterBlock.java index b91ef08b0..4f3db3994 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/AbstractFilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/AbstractFilterBlock.java @@ -31,18 +31,18 @@ public abstract class AbstractFilterBlock extends FilterBlock { public abstract Extent getExtent(); @Override - public int getX() { - return getPosition().getX(); + public int x() { + return getPosition().x(); } @Override - public int getY() { - return getPosition().getY(); + public int y() { + return getPosition().y(); } @Override - public int getZ() { - return getPosition().getZ(); + public int z() { + return getPosition().z(); } @Override @@ -72,12 +72,12 @@ public abstract class AbstractFilterBlock extends FilterBlock { @Override public BlockVector3 getMinimumPoint() { - return at(getX(), getY(), getZ()); + return at(x(), y(), z()); } @Override public BlockVector3 getMaximumPoint() { - return at(getX(), getY(), getZ()); + return at(x(), y(), z()); } @Override @@ -88,7 +88,7 @@ public abstract class AbstractFilterBlock extends FilterBlock { @Override public > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { - if (x == this.getX() && y == this.getY() && z == this.getZ()) { + if (x == this.x() && y == this.y() && z == this.z()) { setFullBlock(block.toBaseBlock()); return true; } @@ -97,7 +97,7 @@ public abstract class AbstractFilterBlock extends FilterBlock { @Override public boolean setBiome(int x, int y, int z, BiomeType biome) { - if (x == this.getX() && y == this.getY() && z == this.getZ()) { + if (x == this.x() && y == this.y() && z == this.z()) { setBiome(biome); return true; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/ArrayFilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/ArrayFilterBlock.java index 4f73d5fa3..362f869ac 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/ArrayFilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/ArrayFilterBlock.java @@ -80,17 +80,17 @@ public class ArrayFilterBlock extends AbstractExtentFilterBlock { } @Override - public int getX() { + public int x() { return x; } @Override - public int getY() { + public int y() { return (heights[index] & 0xFF) + yOffset; } @Override - public int getZ() { + public int z() { return z; } @@ -112,12 +112,12 @@ public class ArrayFilterBlock extends AbstractExtentFilterBlock { @Override public void setBiome(final BiomeType biome) { - getExtent().setBiome(getX(), getY(), getZ(), biome); + getExtent().setBiome(x(), y(), z(), biome); } @Override public BiomeType getBiome() { - return getExtent().getBiomeType(getX(), getY(), getZ()); + return getExtent().getBiomeType(x(), y(), z()); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java index 9a339826a..579f04a9a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java @@ -190,17 +190,17 @@ public class CharFilterBlock extends ChunkFilterBlock { } @Override - public final int getX() { + public final int x() { return xx + x; } @Override - public final int getY() { + public final int y() { return yy + y; } @Override - public final int getZ() { + public final int z() { return zz + z; } @@ -304,7 +304,7 @@ public class CharFilterBlock extends ChunkFilterBlock { if (z > 0) { return states[getArr[index - 16]]; } - return getExtent().getBlock(getX(), getY(), getZ() - 1); + return getExtent().getBlock(x(), y(), z() - 1); } @Override @@ -312,7 +312,7 @@ public class CharFilterBlock extends ChunkFilterBlock { if (x < 15) { return states[getArr[index + 1]]; } - return getExtent().getBlock(getX() + 1, getY(), getZ()); + return getExtent().getBlock(x() + 1, y(), z()); } @Override @@ -320,7 +320,7 @@ public class CharFilterBlock extends ChunkFilterBlock { if (z < 15) { return states[getArr[index + 16]]; } - return getExtent().getBlock(getX(), getY(), getZ() + 1); + return getExtent().getBlock(x(), y(), z() + 1); } @Override @@ -328,7 +328,7 @@ public class CharFilterBlock extends ChunkFilterBlock { if (x > 0) { return states[getArr[index - 1]]; } - return getExtent().getBlock(getX() - 1, getY(), getZ()); + return getExtent().getBlock(x() - 1, y(), z()); } @Override @@ -401,7 +401,7 @@ public class CharFilterBlock extends ChunkFilterBlock { @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { - return setBiome(position.getX(), position.getY(), position.getBlockZ(), biome); + return setBiome(position.x(), position.y(), position.z(), biome); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/FilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/FilterBlock.java index c27d3770a..3565c696f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/FilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/FilterBlock.java @@ -73,60 +73,60 @@ public abstract class FilterBlock extends BlockVector3 implements Extent, TileEn } public BlockState getBlockBelow() { - return getBlock(getX(), getY() - 1, getZ()); + return getBlock(x(), y() - 1, z()); } public BlockState getBlockAbove() { - return getBlock(getX(), getY() + 1, getZ()); + return getBlock(x(), y() + 1, z()); } public BlockState getBlockNorth() { - return getBlock(getX(), getY(), getZ() - 1); + return getBlock(x(), y(), z() - 1); } public BlockState getBlockEast() { - return getBlock(getX() + 1, getY(), getZ()); + return getBlock(x() + 1, y(), z()); } public BlockState getBlockSouth() { - return getBlock(getX(), getY(), getZ() + 1); + return getBlock(x(), y(), z() + 1); } public BlockState getBlockWest() { - return getBlock(getX() - 1, getY(), getZ()); + return getBlock(x() - 1, y(), z()); } public BlockState getBlockRelativeY(int y) { - return getBlock(getX(), getY() + y, getZ()); + return getBlock(x(), y() + y, z()); } @Override - public abstract int getX(); + public abstract int x(); @Override - public abstract int getY(); + public abstract int y(); @Override - public abstract int getZ(); + public abstract int z(); public int getLocalX() { - return getX() & 15; + return x() & 15; } public int getLocalY() { - return getY() & 15; + return y() & 15; } public int getLocalZ() { - return getZ() & 15; + return z() & 15; } public int getChunkX() { - return getX() >> 4; + return x() >> 4; } public int getChunkZ() { - return getZ() >> 4; + return z() >> 4; } /* @@ -204,7 +204,7 @@ public abstract class FilterBlock extends BlockVector3 implements Extent, TileEn @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { - return setBiome(position.getX(), position.getY(), position.getZ(), biome); + return setBiome(position.x(), position.y(), position.z(), biome); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/SingleFilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/SingleFilterBlock.java index 5516ae3bb..83301c4ea 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/SingleFilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/SingleFilterBlock.java @@ -17,17 +17,17 @@ public class SingleFilterBlock extends AbstractSingleFilterBlock { } @Override - public int getX() { + public int x() { return x; } @Override - public int getY() { + public int y() { return y; } @Override - public int getZ() { + public int z() { return z; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/DelegateBlockVector3.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/DelegateBlockVector3.java index b75e157b2..b13aece41 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/DelegateBlockVector3.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/DelegateBlockVector3.java @@ -95,13 +95,8 @@ public class DelegateBlockVector3 extends BlockVector3 { } @Override - public int getX() { - return parent.getX(); - } - - @Override - public int getBlockX() { - return parent.getBlockX(); + public int x() { + return parent.x(); } @Override @@ -110,13 +105,8 @@ public class DelegateBlockVector3 extends BlockVector3 { } @Override - public int getY() { - return parent.getY(); - } - - @Override - public int getBlockY() { - return parent.getBlockY(); + public int y() { + return parent.y(); } @Override @@ -125,13 +115,8 @@ public class DelegateBlockVector3 extends BlockVector3 { } @Override - public int getZ() { - return parent.getZ(); - } - - @Override - public int getBlockZ() { - return parent.getBlockZ(); + public int z() { + return parent.z(); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableBlockVector3.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableBlockVector3.java index 6ebabae1d..e4cfda85a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableBlockVector3.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableBlockVector3.java @@ -21,11 +21,11 @@ public class MutableBlockVector3 extends BlockVector3 { } public MutableBlockVector3(BlockVector3 other) { - this(other.getX(), other.getY(), other.getZ()); + this(other.x(), other.y(), other.z()); } public MutableBlockVector3 setComponents(BlockVector3 other) { - return setComponents(other.getBlockX(), other.getBlockY(), other.getBlockZ()); + return setComponents(other.x(), other.y(), other.z()); } private int x; @@ -47,33 +47,33 @@ public class MutableBlockVector3 extends BlockVector3 { } @Override - public final int getX() { + public final int x() { return x; } @Override - public final int getY() { + public final int y() { return y; } @Override - public final int getZ() { + public final int z() { return z; } @Override public BlockVector3 getMinimum(BlockVector3 v2) { - this.x = Math.min(v2.getX(), x); - this.y = Math.min(v2.getY(), y); - this.z = Math.min(v2.getZ(), z); + this.x = Math.min(v2.x(), x); + this.y = Math.min(v2.y(), y); + this.z = Math.min(v2.z(), z); return this; } @Override public BlockVector3 getMaximum(BlockVector3 v2) { - this.x = Math.max(v2.getX(), x); - this.y = Math.max(v2.getY(), y); - this.z = Math.max(v2.getZ(), z); + this.x = Math.max(v2.x(), x); + this.y = Math.max(v2.y(), y); + this.z = Math.max(v2.z(), z); return this; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableVector3.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableVector3.java index 22d85d38a..3c6ad1334 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableVector3.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableVector3.java @@ -23,7 +23,7 @@ public class MutableVector3 extends Vector3 { } public MutableVector3(Vector3 other) { - this(other.getX(), other.getY(), other.getZ()); + this(other.x(), other.y(), other.z()); } public static MutableVector3 get(int x, int y, int z) { @@ -36,9 +36,9 @@ public class MutableVector3 extends Vector3 { @Override public MutableVector3 setComponents(Vector3 other) { - this.x = other.getX(); - this.y = other.getY(); - this.z = other.getZ(); + this.x = other.x(); + this.y = other.y(); + this.z = other.z(); return this; } @@ -95,17 +95,17 @@ public class MutableVector3 extends Vector3 { } @Override - public double getX() { + public double x() { return x; } @Override - public double getY() { + public double y() { return y; } @Override - public double getZ() { + public double z() { return z; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/OffsetBlockVector3.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/OffsetBlockVector3.java index 044a623de..5e0d0ebe0 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/OffsetBlockVector3.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/OffsetBlockVector3.java @@ -11,18 +11,18 @@ public class OffsetBlockVector3 extends DelegateBlockVector3 { } @Override - public int getX() { - return super.getX() + offset.getX(); + public int x() { + return super.x() + offset.x(); } @Override - public int getY() { - return super.getY() + offset.getY(); + public int y() { + return super.y() + offset.y(); } @Override - public int getZ() { - return super.getZ() + offset.getZ(); + public int z() { + return super.z() + offset.z(); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/Vector3Impl.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/Vector3Impl.java index c1092a881..33706aee5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/Vector3Impl.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/Vector3Impl.java @@ -15,21 +15,21 @@ public class Vector3Impl extends Vector3 { } public Vector3Impl(Vector3 other) { - this(other.getX(), other.getY(), other.getZ()); + this(other.x(), other.y(), other.z()); } @Override - public final double getX() { + public final double x() { return x; } @Override - public final double getY() { + public final double y() { return y; } @Override - public final double getZ() { + public final double z() { return z; } 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 fe95ad3ad..cb5784cce 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 @@ -27,7 +27,7 @@ import java.util.Comparator; /** * An immutable 2-dimensional vector. */ -//FAWE start - un-finalize +//FAWE start - not a record public class BlockVector2 { //FAWE end @@ -122,7 +122,19 @@ public class BlockVector2 { * Get the X coordinate. * * @return the x coordinate + * @since TODO */ + public int x() { + return x; + } + + /** + * Get the X coordinate. + * + * @return the x coordinate + * @deprecated use {@link #x()} instead + */ + @Deprecated(forRemoval = true, since = "TODO") public int getX() { return x; } @@ -131,7 +143,9 @@ public class BlockVector2 { * Get the X coordinate. * * @return the x coordinate + * @deprecated use {@link #x()} instead */ + @Deprecated(forRemoval = true, since = "TODO") public int getBlockX() { return x; } @@ -150,7 +164,19 @@ public class BlockVector2 { * Get the Z coordinate. * * @return the z coordinate + * @since TODO */ + public int z() { + return z; + } + + /** + * Get the Z coordinate. + * + * @return the z coordinate + * @deprecated use {@link #z()} instead + */ + @Deprecated(forRemoval = true, since = "TODO") public int getZ() { return z; } @@ -159,7 +185,9 @@ public class BlockVector2 { * Get the Z coordinate. * * @return the z coordinate + * @deprecated use {@link #z()} instead */ + @Deprecated(forRemoval = true, since = "TODO") public int getBlockZ() { return z; } @@ -598,13 +626,13 @@ public class BlockVector2 { return BlockVector3.at(x, y, z); } + //FAWE start - not a record, need own implementations @Override public boolean equals(Object obj) { - if (!(obj instanceof BlockVector2)) { + if (!(obj instanceof BlockVector2 other)) { return false; } - BlockVector2 other = (BlockVector2) obj; return other.x == this.x && other.z == this.z; } @@ -613,6 +641,7 @@ public class BlockVector2 { public int hashCode() { return (x << 16) ^ z; } + //FAWE end @Override public String toString() { 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 5f1c14842..e48355d63 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 @@ -38,7 +38,9 @@ import static com.sk89q.worldedit.math.BitMath.unpackZ; /** * An immutable 3-dimensional vector. */ +//FAWE start - not a record public abstract class BlockVector3 { +//FAWE end public static final BlockVector3 ZERO = BlockVector3.at(0, 0, 0); public static final BlockVector3 UNIT_X = BlockVector3.at(1, 0, 0); @@ -85,9 +87,9 @@ public abstract class BlockVector3 { } public static boolean isLongPackable(BlockVector3 location) { - return isHorizontallyInBounds(location.getX()) - && isHorizontallyInBounds(location.getZ()) - && WORLD_Y_MIN <= location.getY() && location.getY() <= WORLD_Y_MAX; + return isHorizontallyInBounds(location.x()) + && isHorizontallyInBounds(location.z()) + && WORLD_Y_MIN <= location.y() && location.y() <= WORLD_Y_MAX; } public static void checkLongPackable(BlockVector3 location) { @@ -107,9 +109,9 @@ public abstract class BlockVector3 { private static final class YzxOrderComparator { private static final Comparator YZX_ORDER = - Comparator.comparingInt(BlockVector3::getY) - .thenComparingInt(BlockVector3::getZ) - .thenComparingInt(BlockVector3::getX); + Comparator.comparingInt(BlockVector3::y) + .thenComparingInt(BlockVector3::z) + .thenComparingInt(BlockVector3::x); } @@ -135,57 +137,69 @@ public abstract class BlockVector3 { public long toLongPackedForm() { checkLongPackable(this); - return (getX() & BITS_26) | ((getZ() & BITS_26) << 26) | (((getY() & BITS_12) << (26 + 26))); + return (x() & BITS_26) | ((z() & BITS_26) << 26) | (((y() & BITS_12) << (26 + 26))); } public MutableBlockVector3 mutX(double x) { - return new MutableBlockVector3((int) x, getY(), getZ()); + return new MutableBlockVector3((int) x, y(), z()); } public MutableBlockVector3 mutY(double y) { - return new MutableBlockVector3(getX(), (int) y, getZ()); + return new MutableBlockVector3(x(), (int) y, z()); } public MutableBlockVector3 mutZ(double z) { - return new MutableBlockVector3(getX(), getY(), (int) z); + return new MutableBlockVector3(x(), y(), (int) z); } public MutableBlockVector3 mutX(int x) { - return new MutableBlockVector3(x, getY(), getZ()); + return new MutableBlockVector3(x, y(), z()); } public MutableBlockVector3 mutY(int y) { - return new MutableBlockVector3(getX(), y, getZ()); + return new MutableBlockVector3(x(), y, z()); } public MutableBlockVector3 mutZ(int z) { - return new MutableBlockVector3(getX(), getY(), z); + return new MutableBlockVector3(x(), y(), z); } public BlockVector3 toImmutable() { - return BlockVector3.at(getX(), getY(), getZ()); + return BlockVector3.at(x(), y(), z()); } //FAWE end + //FAWE start - make record getters to abstract methods /** * Get the X coordinate. * * @return the x coordinate + * @since TODO */ - //FAWE start - Made abstract - public abstract int getX(); + public abstract int x(); //FAWE end /** * Get the X coordinate. * * @return the x coordinate + * @deprecated use {@link #x()} instead */ - //FAWE start - getter + @Deprecated(forRemoval = true, since = "TODO") + public int getX() { + return this.x(); //FAWE - access abstract getter instead of local field + } + + /** + * Get the X coordinate. + * + * @return the x coordinate + * @deprecated use {@link #x()} instead + */ + @Deprecated(forRemoval = true, since = "TODO") public int getBlockX() { - return getX(); + return this.x(); //FAWE - access abstract getter instead of local field } - //FAWE end /** * Set the X coordinate. @@ -195,29 +209,42 @@ public abstract class BlockVector3 { */ //FAWE start - getter public BlockVector3 withX(int x) { - return BlockVector3.at(x, getY(), getZ()); + return BlockVector3.at(x, y(), z()); } //FAWE end + + //FAWE start - make record getters to abstract methods /** * Get the Y coordinate. * * @return the y coordinate + * @since TODO */ - //FAWE start - Made abstract - public abstract int getY(); + public abstract int y(); //FAWE end /** * Get the Y coordinate. * * @return the y coordinate + * @deprecated use {@link #y()} instead */ - //FAWE start - getter + @Deprecated(forRemoval = true, since = "TODO") + public int getY() { + return this.y(); //FAWE - access abstract getter instead of local field + } + + /** + * Get the Y coordinate. + * + * @return the y coordinate + * @deprecated use {@link #y()} instead + */ + @Deprecated(forRemoval = true, since = "TODO") public int getBlockY() { - return getY(); + return this.y(); //FAWE - access abstract getter instead of local field } - //FAWE end /** * Set the Y coordinate. @@ -231,25 +258,37 @@ public abstract class BlockVector3 { } //FAWE end + //FAWE start - make record getters to abstract methods /** * Get the Z coordinate. * - * @return the z coordinate + * @return the Z coordinate + * @since TODO */ - //FAWE start - Made abstract - public abstract int getZ(); + public abstract int z(); //FAWE end /** * Get the Z coordinate. * * @return the z coordinate + * @deprecated use {@link #z()} instead */ - //FAWE start - getter - public int getBlockZ() { - return getZ(); + @Deprecated(forRemoval = true, since = "TODO") + public int getZ() { + return this.z(); //FAWE - access abstract getter instead of local field + } + + /** + * Get the Z coordinate. + * + * @return the z coordinate + * @deprecated use {@link #z()} instead + */ + @Deprecated(forRemoval = true, since = "TODO") + public int getBlockZ() { + return this.z(); //FAWE - access abstract getter instead of local field } - //FAWE end /** * Set the Z coordinate. @@ -259,7 +298,7 @@ public abstract class BlockVector3 { */ //FAWE start - getter public BlockVector3 withZ(int z) { - return BlockVector3.at(getX(), getY(), z); + return BlockVector3.at(x(), y(), z); } //FAWE end @@ -271,7 +310,7 @@ public abstract class BlockVector3 { */ //FAWE start - getter public BlockVector3 add(BlockVector3 other) { - return add(other.getX(), other.getY(), other.getZ()); + return add(other.x(), other.y(), other.z()); } //FAWE end @@ -285,7 +324,7 @@ public abstract class BlockVector3 { */ //FAWE start - getter public BlockVector3 add(int x, int y, int z) { - return BlockVector3.at(this.getX() + x, this.getY() + y, this.getZ() + z); + return BlockVector3.at(this.x() + x, this.y() + y, this.z() + z); } //FAWE end @@ -298,14 +337,14 @@ public abstract class BlockVector3 { */ //FAWE start - getter public BlockVector3 add(BlockVector3... others) { - int newX = getX(); - int newY = getY(); - int newZ = getZ(); + int newX = x(); + int newY = y(); + int newZ = z(); for (BlockVector3 other : others) { - newX += other.getX(); - newY += other.getY(); - newZ += other.getZ(); + newX += other.x(); + newY += other.y(); + newZ += other.z(); } return BlockVector3.at(newX, newY, newZ); @@ -321,7 +360,7 @@ public abstract class BlockVector3 { */ //FAWE start - getter public BlockVector3 subtract(BlockVector3 other) { - return subtract(other.getX(), other.getY(), other.getZ()); + return subtract(other.x(), other.y(), other.z()); } //FAWE end @@ -336,7 +375,7 @@ public abstract class BlockVector3 { */ //FAWE start - getter public BlockVector3 subtract(int x, int y, int z) { - return BlockVector3.at(this.getX() - x, this.getY() - y, this.getZ() - z); + return BlockVector3.at(this.x() - x, this.y() - y, this.z() - z); } //FAWE end @@ -349,14 +388,14 @@ public abstract class BlockVector3 { */ //FAWE start - getter public BlockVector3 subtract(BlockVector3... others) { - int newX = getX(); - int newY = getY(); - int newZ = getZ(); + int newX = x(); + int newY = y(); + int newZ = z(); for (BlockVector3 other : others) { - newX -= other.getX(); - newY -= other.getY(); - newZ -= other.getZ(); + newX -= other.x(); + newY -= other.y(); + newZ -= other.z(); } return BlockVector3.at(newX, newY, newZ); @@ -371,7 +410,7 @@ public abstract class BlockVector3 { */ //FAWE start - getter public BlockVector3 multiply(BlockVector3 other) { - return multiply(other.getX(), other.getY(), other.getZ()); + return multiply(other.x(), other.y(), other.z()); } //FAWE end @@ -385,7 +424,7 @@ public abstract class BlockVector3 { */ //FAWE start - getter public BlockVector3 multiply(int x, int y, int z) { - return BlockVector3.at(this.getX() * x, this.getY() * y, this.getZ() * z); + return BlockVector3.at(this.x() * x, this.y() * y, this.z() * z); } //FAWE end @@ -397,14 +436,14 @@ public abstract class BlockVector3 { */ //FAWE start - getter public BlockVector3 multiply(BlockVector3... others) { - int newX = getX(); - int newY = getY(); - int newZ = getZ(); + int newX = x(); + int newY = y(); + int newZ = z(); for (BlockVector3 other : others) { - newX *= other.getX(); - newY *= other.getY(); - newZ *= other.getZ(); + newX *= other.x(); + newY *= other.y(); + newZ *= other.z(); } return BlockVector3.at(newX, newY, newZ); @@ -429,7 +468,7 @@ public abstract class BlockVector3 { */ //FAWE start - getter public BlockVector3 divide(BlockVector3 other) { - return divide(other.getX(), other.getY(), other.getZ()); + return divide(other.x(), other.y(), other.z()); } //FAWE end @@ -443,7 +482,7 @@ public abstract class BlockVector3 { */ //FAWE start - getter public BlockVector3 divide(int x, int y, int z) { - return BlockVector3.at(this.getX() / x, this.getY() / y, this.getZ() / z); + return BlockVector3.at(this.x() / x, this.y() / y, this.z() / z); } //FAWE end @@ -467,7 +506,7 @@ public abstract class BlockVector3 { */ //FAWE start - getter public BlockVector3 shr(int x, int y, int z) { - return at(this.getX() >> x, this.getY() >> y, this.getZ() >> z); + return at(this.x() >> x, this.y() >> y, this.z() >> z); } //FAWE end @@ -491,7 +530,7 @@ public abstract class BlockVector3 { */ //FAWE start - getter public BlockVector3 shl(int x, int y, int z) { - return at(this.getX() << x, this.getY() << y, this.getZ() << z); + return at(this.x() << x, this.y() << y, this.z() << z); } //FAWE end @@ -521,7 +560,7 @@ public abstract class BlockVector3 { */ //FAWE start - getter public int lengthSq() { - return getX() * getX() + getY() * getY() + getZ() * getZ(); + return x() * x() + y() * y() + z() * z(); } //FAWE end @@ -543,9 +582,9 @@ public abstract class BlockVector3 { */ //FAWE start - getter public int distanceSq(BlockVector3 other) { - int dx = other.getX() - getX(); - int dy = other.getY() - getY(); - int dz = other.getZ() - getZ(); + int dx = other.x() - x(); + int dy = other.y() - y(); + int dz = other.z() - z(); return dx * dx + dy * dy + dz * dz; } //FAWE end @@ -559,9 +598,9 @@ public abstract class BlockVector3 { //FAWE start - getter public BlockVector3 normalize() { double len = length(); - double x = this.getX() / len; - double y = this.getY() / len; - double z = this.getZ() / len; + double x = this.x() / len; + double y = this.y() / len; + double z = this.z() / len; return BlockVector3.at(x, y, z); } //FAWE end @@ -574,7 +613,7 @@ public abstract class BlockVector3 { */ //FAWE start - getter public double dot(BlockVector3 other) { - return getX() * other.getX() + getY() * other.getY() + getZ() * other.getZ(); + return x() * other.x() + y() * other.y() + z() * other.z(); } //FAWE end @@ -587,9 +626,9 @@ public abstract class BlockVector3 { //FAWE start - getter public BlockVector3 cross(BlockVector3 other) { return new BlockVector3Imp( - getY() * other.getZ() - getZ() * other.getY(), - getZ() * other.getX() - getX() * other.getZ(), - getX() * other.getY() - getY() * other.getX() + y() * other.z() - z() * other.y(), + z() * other.x() - x() * other.z(), + x() * other.y() - y() * other.x() ); } //FAWE end @@ -603,8 +642,7 @@ public abstract class BlockVector3 { */ //FAWE start - getter public boolean containedWithin(BlockVector3 min, BlockVector3 max) { - return getX() >= min.getX() && getX() <= max.getX() && getY() >= min.getY() && getY() <= max - .getY() && getZ() >= min.getZ() && getZ() <= max.getZ(); + return x() >= min.x() && x() <= max.x() && y() >= min.y() && y() <= max.y() && z() >= min.z() && z() <= max.z(); } //FAWE end @@ -618,11 +656,11 @@ public abstract class BlockVector3 { //FAWE start - getter public BlockVector3 clampY(int min, int max) { checkArgument(min <= max, "minimum cannot be greater than maximum"); - if (getY() < min) { - return BlockVector3.at(getX(), min, getZ()); + if (y() < min) { + return BlockVector3.at(x(), min, z()); } - if (getY() > max) { - return BlockVector3.at(getX(), max, getZ()); + if (y() > max) { + return BlockVector3.at(x(), max, z()); } return this; } @@ -668,7 +706,7 @@ public abstract class BlockVector3 { */ //FAWE start - getter public BlockVector3 abs() { - return BlockVector3.at(Math.abs(getX()), Math.abs(getY()), Math.abs(getZ())); + return BlockVector3.at(Math.abs(x()), Math.abs(y()), Math.abs(z())); } //FAWE end @@ -686,8 +724,8 @@ public abstract class BlockVector3 { //FAWE start - getter public BlockVector3 transform2D(double angle, double aboutX, double aboutZ, double translateX, double translateZ) { angle = Math.toRadians(angle); - double x = this.getX() - aboutX; - double z = this.getZ() - aboutZ; + double x = this.x() - aboutX; + double z = this.z() - aboutZ; double cos = Math.cos(angle); double sin = Math.sin(angle); double x2 = x * cos - z * sin; @@ -695,7 +733,7 @@ public abstract class BlockVector3 { return BlockVector3.at( x2 + aboutX + translateX, - getY(), + y(), z2 + aboutZ + translateZ ); } @@ -707,16 +745,16 @@ public abstract class BlockVector3 { * @return pitch in radians */ public double toPitch() { - double x = getX(); - double z = getZ(); + double x = x(); + double z = z(); if (x == 0 && z == 0) { - return getY() > 0 ? -90 : 90; + return y() > 0 ? -90 : 90; } else { double x2 = x * x; double z2 = z * z; double xz = Math.sqrt(x2 + z2); - return Math.toDegrees(Math.atan(-getY() / xz)); + return Math.toDegrees(Math.atan(-y() / xz)); } } @@ -726,8 +764,8 @@ public abstract class BlockVector3 { * @return yaw in radians */ public double toYaw() { - double x = getX(); - double z = getZ(); + double x = x(); + double z = z(); double t = Math.atan2(-x, z); double tau = 2 * Math.PI; @@ -744,9 +782,9 @@ public abstract class BlockVector3 { //FAWE start - getter public BlockVector3 getMinimum(BlockVector3 v2) { return new BlockVector3Imp( - Math.min(getX(), v2.getX()), - Math.min(getY(), v2.getY()), - Math.min(getZ(), v2.getZ()) + Math.min(x(), v2.x()), + Math.min(y(), v2.y()), + Math.min(z(), v2.z()) ); } //FAWE end @@ -760,9 +798,9 @@ public abstract class BlockVector3 { //FAWE start - getter public BlockVector3 getMaximum(BlockVector3 v2) { return new BlockVector3Imp( - Math.max(getX(), v2.getX()), - Math.max(getY(), v2.getY()), - Math.max(getZ(), v2.getZ()) + Math.max(x(), v2.x()), + Math.max(y(), v2.y()), + Math.max(z(), v2.z()) ); } //FAWE end @@ -815,19 +853,19 @@ public abstract class BlockVector3 { } public CompoundTag getNbtData(Extent orDefault) { - return orDefault.getFullBlock(getX(), getY(), getZ()).getNbtData(); + return orDefault.getFullBlock(x(), y(), z()).getNbtData(); } public BlockState getOrdinalBelow(Extent orDefault) { - return orDefault.getBlock(getX(), getY() - 1, getZ()); + return orDefault.getBlock(x(), y() - 1, z()); } public BlockState getStateAbove(Extent orDefault) { - return orDefault.getBlock(getX(), getY() + 1, getZ()); + return orDefault.getBlock(x(), y() + 1, z()); } public BlockState getStateRelativeY(Extent orDefault, final int y) { - return orDefault.getBlock(getX(), getY() + y, getZ()); + return orDefault.getBlock(x(), y() + y, z()); } /** @@ -836,21 +874,21 @@ public abstract class BlockVector3 { * @return a new {@link BlockVector2} */ public BlockVector2 toBlockVector2() { - return BlockVector2.at(getX(), getZ()); + return BlockVector2.at(x(), z()); } public Vector3 toVector3() { - return Vector3.at(getX(), getY(), getZ()); + return Vector3.at(x(), y(), z()); } + //FAWE start - not a record, need own implementations @Override public boolean equals(Object obj) { - if (!(obj instanceof BlockVector3)) { + if (!(obj instanceof final BlockVector3 other)) { return false; } - BlockVector3 other = (BlockVector3) obj; - return other.getX() == this.getX() && other.getY() == this.getY() && other.getZ() == this.getZ(); + return other.x() == this.x() && other.y() == this.y() && other.z() == this.z(); } public final boolean equals(BlockVector3 other) { @@ -858,17 +896,18 @@ public abstract class BlockVector3 { return false; } - return other.getX() == this.getX() && other.getY() == this.getY() && other.getZ() == this.getZ(); + return other.x() == this.x() && other.y() == this.y() && other.z() == this.z(); } @Override public int hashCode() { - return (getX() ^ (getZ() << 12)) ^ (getY() << 24); + return (x() ^ (z() << 12)) ^ (y() << 24); } + //FAWE end @Override public String toString() { - return "(" + getX() + ", " + getY() + ", " + getZ() + ")"; + return "(" + x() + ", " + y() + ", " + z() + ")"; } /** @@ -877,7 +916,7 @@ public abstract class BlockVector3 { * @return string */ public String toParserString() { - return getX() + "," + getY() + "," + getZ(); + return x() + "," + y() + "," + z(); } //Used by VS fork diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java index ab202e83b..5ec2f4fe2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java @@ -56,33 +56,33 @@ public final class BlockVector3Imp extends BlockVector3 { } @Override - public final int getX() { + public int x() { return x; } @Override - public final int getY() { + public int y() { return y; } @Override - public final int getZ() { + public int z() { return z; } @Override public int hashCode() { - return (getX() ^ (getZ() << 12)) ^ (getY() << 24); + return (x() ^ (z() << 12)) ^ (y() << 24); } @Override - public final BlockVector3 toImmutable() { + public BlockVector3 toImmutable() { return this; } @Override public String toString() { - return "(" + getX() + ", " + getY() + ", " + getZ() + ")"; + return "(" + x() + ", " + y() + ", " + z() + ")"; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector2.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector2.java index d680b0c0d..9d08676f9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector2.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector2.java @@ -19,12 +19,13 @@ package com.sk89q.worldedit.math; +import com.fastasyncworldedit.core.util.MathMan; import com.sk89q.worldedit.math.transform.AffineTransform; /** * An immutable 2-dimensional vector. */ -public final class Vector2 { +public record Vector2(double x, double z) { public static final Vector2 ZERO = new Vector2(0, 0); public static final Vector2 UNIT_X = new Vector2(1, 0); @@ -50,29 +51,27 @@ public final class Vector2 { return new Vector2(x, z); } - private final double x; - private final double z; - - /** - * Construct an instance. - * - * @param x the X coordinate - * @param z the Z coordinate - */ - private Vector2(double x, double z) { - this.x = x; - this.z = z; - } - /** * Get the X coordinate. * * @return the x coordinate + * @deprecated use {@link #x()} instead */ + @Deprecated(forRemoval = true, since = "TODO") public double getX() { return x; } + /** + * Get the X coordinate, aligned to the block grid. + * + * @return the block-aligned x coordinate + * @since TODO + */ + public int blockX() { + return MathMan.roundInt(x); + } + /** * Set the X coordinate. * @@ -83,11 +82,23 @@ public final class Vector2 { return Vector2.at(x, z); } + /** + * Get the Z coordinate, aligned to the block grid. + * + * @return the block-aligned z coordinate + * @since TODO + */ + public int blockZ() { + return MathMan.roundInt(z); + } + /** * Get the Z coordinate. * * @return the z coordinate + * @deprecated use {@link #z()} instead */ + @Deprecated(forRemoval = true, since = "TODO") public double getZ() { return z; } @@ -458,24 +469,6 @@ public final class Vector2 { return Vector3.at(x, y, z); } - @Override - public boolean equals(Object obj) { - if (!(obj instanceof Vector2)) { - return false; - } - - Vector2 other = (Vector2) obj; - return other.x == this.x && other.z == this.z; - - } - - @Override - public int hashCode() { - //FAWE start - XOR over x z calc - return (int) x << 16 ^ (int) z; - //FAWE end - } - @Override public String toString() { return "(" + x + ", " + z + ")"; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector3.java index 5a4d550b4..898bb5241 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector3.java @@ -32,7 +32,9 @@ import static com.google.common.base.Preconditions.checkArgument; /** * An immutable 3-dimensional vector. */ +//FAWE start - not a record, make abstract public abstract class Vector3 { +//FAWE end public static final Vector3 ZERO = Vector3.at(0, 0, 0); public static final Vector3 UNIT_X = Vector3.at(1, 0, 0); @@ -69,9 +71,9 @@ public abstract class Vector3 { private static final Comparator YZX_ORDER = (a, b) -> { return ComparisonChain.start() - .compare(a.getY(), b.getY()) - .compare(a.getZ(), b.getZ()) - .compare(a.getX(), b.getX()) + .compare(a.y(), b.y()) + .compare(a.z(), b.z()) + .compare(a.x(), b.x()) .result(); }; @@ -96,7 +98,7 @@ public abstract class Vector3 { * @return the x coordinate */ public int getBlockX() { - return MathMan.roundInt(getX()); + return MathMan.roundInt(x()); } /** @@ -105,7 +107,7 @@ public abstract class Vector3 { * @return the y coordinate */ public int getBlockY() { - return MathMan.roundInt(getY()); + return MathMan.roundInt(y()); } /** @@ -114,7 +116,7 @@ public abstract class Vector3 { * @return the z coordinate */ public int getBlockZ() { - return MathMan.roundInt(getZ()); + return MathMan.roundInt(z()); } public MutableVector3 setComponents(Vector3 other) { @@ -130,27 +132,27 @@ public abstract class Vector3 { } public MutableVector3 mutX(int x) { - return new MutableVector3(x, getY(), getZ()); + return new MutableVector3(x, y(), z()); } public MutableVector3 mutX(double x) { - return new MutableVector3(x, getY(), getZ()); + return new MutableVector3(x, y(), z()); } public MutableVector3 mutY(int y) { - return new MutableVector3(getX(), y, getZ()); + return new MutableVector3(x(), y, z()); } public MutableVector3 mutY(double y) { - return new MutableVector3(getX(), y, getZ()); + return new MutableVector3(x(), y, z()); } public MutableVector3 mutZ(int z) { - return new MutableVector3(getX(), getY(), z); + return new MutableVector3(x(), y(), z); } public MutableVector3 mutZ(double z) { - return new MutableVector3(getX(), getY(), z); + return new MutableVector3(x(), y(), z); } //FAWE end @@ -158,10 +160,29 @@ public abstract class Vector3 { * Get the X coordinate. * * @return the x coordinate + * @since TODO */ - //FAWE start - made abstract - public abstract double getX(); - //FAWE end + public abstract double x(); + + /** + * Get the X coordinate, aligned to the block grid. + * + * @return the block-aligned x coordinate + */ + public int blockX() { + return MathMan.roundInt(this.x()); + } + + /** + * Get the X coordinate. + * + * @return the x coordinate + * @deprecated use {@link #x()} instead + */ + @Deprecated(forRemoval = true, since = "TODO") + public double getX() { + return this.x(); + } /** * Set the X coordinate. @@ -171,18 +192,38 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 withX(double x) { - return Vector3.at(x, getY(), getZ()); + return Vector3.at(x, y(), z()); } //FAWE end + /** * Get the Y coordinate. * * @return the y coordinate + * @since TODO */ - //FAWE start - made abstract - public abstract double getY(); - //FAWE end + public abstract double y(); + + /** + * Get the Y coordinate, aligned to the block grid. + * + * @return the block-aligned y coordinate + */ + public int blockY() { + return MathMan.roundInt(this.y()); + } + + /** + * Get the Y coordinate. + * + * @return the y coordinate + * @deprecated use {@link #y()} instead + */ + @Deprecated(forRemoval = true, since = "TODO") + public double getY() { + return this.y(); + } /** * Set the Y coordinate. @@ -192,7 +233,7 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 withY(double y) { - return Vector3.at(getX(), y, getZ()); + return Vector3.at(x(), y, z()); } //FAWE end @@ -200,10 +241,29 @@ public abstract class Vector3 { * Get the Z coordinate. * * @return the z coordinate + * @since TODO */ - //FAWE start - made abstract - public abstract double getZ(); - //FAWE end + public abstract double z(); + + /** + * Get the Z coordinate, aligned to the block grid. + * + * @return the block-aligned z coordinate + */ + public int blockZ() { + return MathMan.roundInt(this.z()); + } + + /** + * Get the Z coordinate. + * + * @return the z coordinate + * @deprecated use {@link #z()} instead + */ + @Deprecated(forRemoval = true, since = "TODO") + public double getZ() { + return this.z(); + } /** * Set the Z coordinate. @@ -213,7 +273,7 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 withZ(double z) { - return Vector3.at(getX(), getY(), z); + return Vector3.at(x(), y(), z); } //FAWE end @@ -225,7 +285,7 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 add(Vector3 other) { - return add(other.getX(), other.getY(), other.getZ()); + return add(other.x(), other.y(), other.z()); } //FAWE end @@ -239,7 +299,7 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 add(double x, double y, double z) { - return Vector3.at(this.getX() + x, this.getY() + y, this.getZ() + z); + return Vector3.at(this.x() + x, this.y() + y, this.z() + z); } //FAWE end @@ -252,14 +312,14 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 add(Vector3... others) { - double newX = getX(); - double newY = getY(); - double newZ = getZ(); + double newX = x(); + double newY = y(); + double newZ = z(); for (Vector3 other : others) { - newX += other.getX(); - newY += other.getY(); - newZ += other.getZ(); + newX += other.x(); + newY += other.y(); + newZ += other.z(); } return Vector3.at(newX, newY, newZ); @@ -275,7 +335,7 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 subtract(Vector3 other) { - return subtract(other.getX(), other.getY(), other.getZ()); + return subtract(other.x(), other.y(), other.z()); } //FAWE end @@ -290,7 +350,7 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 subtract(double x, double y, double z) { - return Vector3.at(this.getX() - x, this.getY() - y, this.getZ() - z); + return Vector3.at(this.x() - x, this.y() - y, this.z() - z); } //FAWE end @@ -303,14 +363,14 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 subtract(Vector3... others) { - double newX = getX(); - double newY = getY(); - double newZ = getZ(); + double newX = x(); + double newY = y(); + double newZ = z(); for (Vector3 other : others) { - newX -= other.getX(); - newY -= other.getY(); - newZ -= other.getZ(); + newX -= other.x(); + newY -= other.y(); + newZ -= other.z(); } return Vector3.at(newX, newY, newZ); @@ -325,7 +385,7 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 multiply(Vector3 other) { - return multiply(other.getX(), other.getY(), other.getZ()); + return multiply(other.x(), other.y(), other.z()); } //FAWE end @@ -339,7 +399,7 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 multiply(double x, double y, double z) { - return Vector3.at(this.getX() * x, this.getY() * y, this.getZ() * z); + return Vector3.at(this.x() * x, this.y() * y, this.z() * z); } //FAWE end @@ -351,14 +411,14 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 multiply(Vector3... others) { - double newX = getX(); - double newY = getY(); - double newZ = getZ(); + double newX = x(); + double newY = y(); + double newZ = z(); for (Vector3 other : others) { - newX *= other.getX(); - newY *= other.getY(); - newZ *= other.getZ(); + newX *= other.x(); + newY *= other.y(); + newZ *= other.z(); } return Vector3.at(newX, newY, newZ); @@ -383,7 +443,7 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 divide(Vector3 other) { - return divide(other.getX(), other.getY(), other.getZ()); + return divide(other.x(), other.y(), other.z()); } //FAWE end @@ -397,7 +457,7 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 divide(double x, double y, double z) { - return Vector3.at(this.getX() / x, this.getY() / y, this.getZ() / z); + return Vector3.at(this.x() / x, this.y() / y, this.z() / z); } //FAWE end @@ -427,7 +487,7 @@ public abstract class Vector3 { */ //FAWE start - getter public double lengthSq() { - return getX() * getX() + getY() * getY() + getZ() * getZ(); + return x() * x() + y() * y() + z() * z(); } //FAWE end @@ -449,9 +509,9 @@ public abstract class Vector3 { */ //FAWE start - getter public double distanceSq(Vector3 other) { - double dx = other.getX() - getX(); - double dy = other.getY() - getY(); - double dz = other.getZ() - getZ(); + double dx = other.x() - x(); + double dy = other.y() - y(); + double dz = other.z() - z(); return dx * dx + dy * dy + dz * dz; } //FAWE end @@ -474,7 +534,7 @@ public abstract class Vector3 { */ //FAWE start - getter public double dot(Vector3 other) { - return getX() * other.getX() + getY() * other.getY() + getZ() * other.getZ(); + return x() * other.x() + y() * other.y() + z() * other.z(); } //FAWE end @@ -487,9 +547,9 @@ public abstract class Vector3 { //FAWE start - getter public Vector3 cross(Vector3 other) { return Vector3.at( - getY() * other.getZ() - getZ() * other.getY(), - getZ() * other.getX() - getX() * other.getZ(), - getX() * other.getY() - getY() * other.getX() + y() * other.z() - z() * other.y(), + z() * other.x() - x() * other.z(), + x() * other.y() - y() * other.x() ); } //FAWE end @@ -503,8 +563,7 @@ public abstract class Vector3 { */ //FAWE start - getter public boolean containedWithin(Vector3 min, Vector3 max) { - return getX() >= min.getX() && getX() <= max.getX() && getY() >= min.getY() && getY() <= max.getY() && getZ() >= min.getZ() && getZ() <= max - .getZ(); + return x() >= min.x() && x() <= max.x() && y() >= min.y() && y() <= max.y() && z() >= min.z() && z() <= max.z(); } //FAWE end @@ -518,11 +577,11 @@ public abstract class Vector3 { //FAWE start - getter public Vector3 clampY(int min, int max) { checkArgument(min <= max, "minimum cannot be greater than maximum"); - if (getY() < min) { - return Vector3.at(getX(), min, getZ()); + if (y() < min) { + return Vector3.at(x(), min, z()); } - if (getY() > max) { - return Vector3.at(getX(), max, getZ()); + if (y() > max) { + return Vector3.at(x(), max, z()); } return this; } @@ -535,7 +594,7 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 floor() { - return Vector3.at(Math.floor(getX()), Math.floor(getY()), Math.floor(getZ())); + return Vector3.at(Math.floor(x()), Math.floor(y()), Math.floor(z())); } //FAWE end @@ -546,7 +605,7 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 ceil() { - return Vector3.at(Math.ceil(getX()), Math.ceil(getY()), Math.ceil(getZ())); + return Vector3.at(Math.ceil(x()), Math.ceil(y()), Math.ceil(z())); } //FAWE end @@ -559,7 +618,7 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 round() { - return Vector3.at(Math.floor(getX() + 0.5), Math.floor(getY() + 0.5), Math.floor(getZ() + 0.5)); + return Vector3.at(Math.floor(x() + 0.5), Math.floor(y() + 0.5), Math.floor(z() + 0.5)); } //FAWE end @@ -570,7 +629,7 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 roundHalfUp() { - return Vector3.at(MathUtils.roundHalfUp(getX()), MathUtils.roundHalfUp(getY()), MathUtils.roundHalfUp(getZ())); + return Vector3.at(MathUtils.roundHalfUp(x()), MathUtils.roundHalfUp(y()), MathUtils.roundHalfUp(z())); } //FAWE end @@ -582,7 +641,7 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector3 abs() { - return Vector3.at(Math.abs(getX()), Math.abs(getY()), Math.abs(getZ())); + return Vector3.at(Math.abs(x()), Math.abs(y()), Math.abs(z())); } //FAWE end @@ -600,8 +659,8 @@ public abstract class Vector3 { //FAWE start - getter public Vector3 transform2D(double angle, double aboutX, double aboutZ, double translateX, double translateZ) { angle = Math.toRadians(angle); - double x = this.getX() - aboutX; - double z = this.getZ() - aboutZ; + double x = this.x() - aboutX; + double z = this.z() - aboutZ; double cos = Math.cos(angle); double sin = Math.sin(angle); double x2 = x * cos - z * sin; @@ -609,7 +668,7 @@ public abstract class Vector3 { return Vector3.at( x2 + aboutX + translateX, - getY(), + y(), z2 + aboutZ + translateZ ); } @@ -621,16 +680,16 @@ public abstract class Vector3 { * @return pitch in radians */ public double toPitch() { - double x = getX(); - double z = getZ(); + double x = x(); + double z = z(); if (x == 0 && z == 0) { - return getY() > 0 ? -90 : 90; + return y() > 0 ? -90 : 90; } else { double x2 = x * x; double z2 = z * z; double xz = Math.sqrt(x2 + z2); - return Math.toDegrees(Math.atan(-getY() / xz)); + return Math.toDegrees(Math.atan(-y() / xz)); } } @@ -640,8 +699,8 @@ public abstract class Vector3 { * @return yaw in radians */ public double toYaw() { - double x = getX(); - double z = getZ(); + double x = x(); + double z = z(); double t = Math.atan2(-x, z); double tau = 2 * Math.PI; @@ -658,9 +717,9 @@ public abstract class Vector3 { //FAWE start - getter public Vector3 getMinimum(Vector3 v2) { return Vector3.at( - Math.min(getX(), v2.getX()), - Math.min(getY(), v2.getY()), - Math.min(getZ(), v2.getZ()) + Math.min(x(), v2.x()), + Math.min(y(), v2.y()), + Math.min(z(), v2.z()) ); } //FAWE end @@ -674,9 +733,9 @@ public abstract class Vector3 { //FAWE start - getter public Vector3 getMaximum(Vector3 v2) { return Vector3.at( - Math.max(getX(), v2.getX()), - Math.max(getY(), v2.getY()), - Math.max(getZ(), v2.getZ()) + Math.max(x(), v2.x()), + Math.max(y(), v2.y()), + Math.max(z(), v2.z()) ); } //FAWE end @@ -700,7 +759,7 @@ public abstract class Vector3 { */ //FAWE start - getter public BlockVector3 toBlockPoint() { - return toBlockPoint(getX(), getY(), getZ()); + return toBlockPoint(x(), y(), z()); } //FAWE end @@ -711,24 +770,20 @@ public abstract class Vector3 { */ //FAWE start - getter public Vector2 toVector2() { - return Vector2.at(getX(), getZ()); + return Vector2.at(x(), z()); } //FAWE end + //FAWE start - not a record, need own implementations @Override public boolean equals(Object obj) { - if (!(obj instanceof Vector3)) { + if (!(obj instanceof final Vector3 other)) { return false; } - Vector3 other = (Vector3) obj; - //FAWE start - getter - return other.getX() == this.getX() && other.getY() == this.getY() && other.getZ() == this.getZ(); - //FAWE end + return other.x() == this.x() && other.y() == this.y() && other.z() == this.z(); } - //FAWE start - /** * Tests if vectors are equal, accounting for floating point errors * @@ -741,28 +796,27 @@ public abstract class Vector3 { } // Minecraft deals in whole blocks, thus any difference smaller than this is unnecessary - if (Math.abs(getX() - other.getX()) > 0.000001d) { + if (Math.abs(x() - other.x()) > 0.000001d) { return false; } - if (Math.abs(getY() - other.getY()) > 0.000001d) { + if (Math.abs(y() - other.y()) > 0.000001d) { return false; } - return !(Math.abs(getZ() - other.getZ()) > 0.000001d); + return !(Math.abs(z() - other.z()) > 0.000001d); + } + + @Override + public int hashCode() { + return (int) x() ^ (int) z() << 12 ^ (int) y() << 24; } //FAWE end - @Override - //FAWE start - XOR over get calculating all values independently - public int hashCode() { - return (int) getX() ^ (int) getZ() << 12 ^ (int) getY() << 24; - } - @Override public String toString() { //FAWE start - getter & ternary - String x = (getX() == getBlockX() ? "" + getBlockX() : "" + getX()); - String y = (getY() == getBlockY() ? "" + getBlockY() : "" + getY()); - String z = (getZ() == getBlockZ() ? "" + getBlockZ() : "" + getZ()); + String x = (x() == blockX() ? "" + blockX() : "" + x()); + String y = (y() == blockY() ? "" + blockY() : "" + y()); + String z = (z() == blockZ() ? "" + blockZ() : "" + z()); //FAWE end return "(" + x + ", " + y + ", " + z + ")"; } @@ -774,7 +828,7 @@ public abstract class Vector3 { */ //FAWE start - getter public String toParserString() { - return getX() + "," + getY() + "," + getZ(); + return x() + "," + y() + "," + z(); } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/Location.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/Location.java index 3a3cd6fb8..52c1a3e62 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/Location.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/Location.java @@ -302,11 +302,11 @@ public class Location extends Vector3Impl { @Override public Location clampY(int min, int max) { checkArgument(min <= max, "minimum cannot be greater than maximum"); - if (getY() < min) { - return new Location(extent, getX(), min, getZ()); + if (y() < min) { + return new Location(extent, x(), min, z()); } - if (getY() > max) { - return new Location(extent, getX(), max, getZ()); + if (y() > max) { + return new Location(extent, x(), max, z()); } return this; @@ -331,13 +331,13 @@ public class Location extends Vector3Impl { return false; } //FAWE start - if (this.getX() != location.getX()) { + if (this.x() != location.x()) { return false; } - if (this.getZ() != location.getZ()) { + if (this.z() != location.z()) { return false; } - if (this.getY() != location.getY()) { + if (this.y() != location.y()) { return false; } return extent.equals(location.extent); From 5225dddaa6dd58d3b854a1a83964640f431cc3d0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 00:23:10 +0000 Subject: [PATCH 254/466] Update dependency paperweight-userdev to v1.20.6-R0.1-20240526.222003-87 --- worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts index 80c044f91..8f97a8454 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/ - the().paperDevBundle("1.20.6-R0.1-20240523.202134-70") + the().paperDevBundle("1.20.6-R0.1-20240526.222003-87") compileOnly(libs.paperlib) } From df92febf7b911d49f4c2ce53a16c6c200a36d001 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 00:23:05 +0000 Subject: [PATCH 255/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.2.11 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 639b7b010..6d7a9bd85 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.2.9" +towny = "0.100.2.11" plotsquared = "7.3.8" # Third party From e9866fb4d7ed7fb8103df1b6e18d3f387f74411f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 03:21:30 +0000 Subject: [PATCH 256/466] Update dependency commons-cli:commons-cli to v1.8.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6d7a9bd85..38f8f3f32 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -35,7 +35,7 @@ jlibnoise = "1.0.0" jchronic = "0.2.4a" lz4-java = "1.8.0" lz4-stream = "1.0.0" -commons-cli = "1.7.0" +commons-cli = "1.8.0" paperlib = "1.0.8" paster = "1.1.6" vault = "1.7.1" From 73186856131c51244a0e1c00d89e6fe2d1ccc6c4 Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Mon, 27 May 2024 21:32:09 +0200 Subject: [PATCH 257/466] fix: ClassCastException on spigot (#2751) fix: ClassCastException on spigot due to method change --- .../impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java index 128897111..4f934129e 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java @@ -345,10 +345,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { .getChunkSource() .getChunkAtIfLoadedImmediately(chunkX, chunkZ); } else { - levelChunk = ((Optional) ((Either) chunkHolder - .getTickingChunkFuture() // method is not present with new paper chunk system - .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left()) - .orElse(null); + levelChunk = chunkHolder.getTickingChunkFuture() + .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).orElse(null); } if (levelChunk == null) { return; From 36d2c85fdb850fa6b20ba0d12d2cee4a757e05cb Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Mon, 27 May 2024 18:48:46 +0100 Subject: [PATCH 258/466] chore: address deprecations in vector classes --- .../ext/fawe/v1_19_R3/PaperweightAdapter.java | 17 +- .../fawe/v1_19_R3/PaperweightFaweAdapter.java | 2 +- .../fawe/v1_19_R3/PaperweightGetBlocks.java | 6 +- .../ext/fawe/v1_20_R1/PaperweightAdapter.java | 16 +- .../fawe/v1_20_R1/PaperweightFaweAdapter.java | 2 +- .../fawe/v1_20_R1/PaperweightGetBlocks.java | 6 +- .../ext/fawe/v1_20_R2/PaperweightAdapter.java | 16 +- .../fawe/v1_20_R2/PaperweightFaweAdapter.java | 2 +- .../fawe/v1_20_R2/PaperweightGetBlocks.java | 6 +- .../ext.fawe/v1_20_R3/PaperweightAdapter.java | 16 +- .../fawe/v1_20_R3/PaperweightFaweAdapter.java | 2 +- .../fawe/v1_20_R3/PaperweightGetBlocks.java | 6 +- .../ext.fawe/v1_20_R4/PaperweightAdapter.java | 16 +- .../fawe/v1_20_R4/PaperweightFaweAdapter.java | 2 +- .../fawe/v1_20_R4/PaperweightGetBlocks.java | 6 +- .../bukkit/adapter/IBukkitAdapter.java | 4 +- .../bukkit/adapter/Regenerator.java | 24 +- .../bukkit/regions/WorldGuardFeature.java | 2 +- .../FaweDelegateSchematicHandler.java | 18 +- .../plotsquared/PlotSquaredFeature.java | 4 +- .../sk89q/worldedit/bukkit/BukkitAdapter.java | 8 +- .../sk89q/worldedit/bukkit/BukkitPlayer.java | 8 +- .../sk89q/worldedit/bukkit/BukkitWorld.java | 30 +-- .../com/fastasyncworldedit/core/FaweAPI.java | 8 +- .../core/command/tool/brush/BlendBall.java | 6 +- .../command/tool/brush/CatenaryBrush.java | 6 +- .../core/command/tool/brush/CommandBrush.java | 6 +- .../command/tool/brush/CopyPastaBrush.java | 4 +- .../core/command/tool/brush/ErodeBrush.java | 20 +- .../command/tool/brush/FallingSphere.java | 6 +- .../core/command/tool/brush/InspectBrush.java | 8 +- .../core/command/tool/brush/RecurseBrush.java | 4 +- .../core/command/tool/brush/RockBrush.java | 12 +- .../core/command/tool/brush/ScatterBrush.java | 8 +- .../command/tool/brush/ScatterCommand.java | 6 +- .../tool/brush/ScatterOverlayBrush.java | 8 +- .../core/command/tool/brush/ShatterBrush.java | 12 +- .../core/command/tool/brush/SplineBrush.java | 6 +- .../command/tool/brush/SurfaceSpline.java | 20 +- .../command/tool/sweep/ClipboardSpline.java | 10 +- .../core/command/tool/sweep/Spline.java | 4 +- .../core/command/tool/sweep/SweepBrush.java | 4 +- .../core/database/RollbackDatabase.java | 36 +-- .../core/extent/BlockTranslateExtent.java | 4 +- .../core/extent/FaweRegionExtent.java | 10 +- .../core/extent/HistoryExtent.java | 4 +- .../core/extent/LimitExtent.java | 4 +- .../core/extent/PositionTransformExtent.java | 28 +-- .../core/extent/ProcessedWEExtent.java | 4 +- .../core/extent/SourceMaskExtent.java | 4 +- .../core/extent/TemporalExtent.java | 6 +- .../core/extent/TransformExtent.java | 30 +-- .../clipboard/CPUOptimizedClipboard.java | 4 +- .../clipboard/DiskOptimizedClipboard.java | 22 +- .../clipboard/MemoryOptimizedClipboard.java | 4 +- .../extent/clipboard/SimpleClipboard.java | 6 +- .../extent/clipboard/WorldCopyClipboard.java | 2 +- .../clipboard/io/FastSchematicReader.java | 4 +- .../clipboard/io/FastSchematicWriter.java | 24 +- .../io/schematic/MinecraftStructure.java | 6 +- .../clipboard/io/schematic/PNGWriter.java | 6 +- .../core/extent/filter/ArrayImageMask.java | 2 +- .../block/AbstractSingleFilterBlock.java | 6 +- .../EntityInBlockRemovingProcessor.java | 6 +- .../processor/lighting/NMSRelighter.java | 58 ++--- .../extent/transform/OffsetTransform.java | 12 +- .../transform/RandomOffsetTransform.java | 12 +- .../core/extent/transform/ScaleTransform.java | 64 ++--- .../extent/transform/SelectTransform.java | 4 +- .../core/function/SurfaceRegionFunction.java | 4 +- .../core/function/block/BiomeCopy.java | 10 +- .../core/function/generator/CavesGen.java | 4 +- .../core/function/generator/GenBase.java | 4 +- .../core/function/generator/SchemGen.java | 2 +- .../core/function/mask/AdjacentAnyMask.java | 6 +- .../core/function/mask/AdjacentMask.java | 6 +- .../core/function/mask/AngleMask.java | 18 +- .../core/function/mask/CachedMask.java | 12 +- .../core/function/mask/ImageBrushMask.java | 14 +- .../core/function/mask/LayerBrushMask.java | 18 +- .../core/function/mask/PlaneMask.java | 18 +- .../core/function/mask/RadiusMask.java | 6 +- .../core/function/mask/SimplexMask.java | 2 +- .../core/function/mask/StencilBrushMask.java | 12 +- .../core/function/mask/SurfaceAngleMask.java | 14 +- .../core/function/mask/WallMakeMask.java | 4 +- .../core/function/mask/WallMask.java | 6 +- .../core/function/mask/XAxisMask.java | 4 +- .../core/function/mask/YAxisMask.java | 4 +- .../core/function/mask/ZAxisMask.java | 4 +- .../function/pattern/AngleColorPattern.java | 6 +- .../core/function/pattern/AnglePattern.java | 6 +- .../function/pattern/BufferedPattern2D.java | 2 +- .../function/pattern/ExpressionPattern.java | 2 +- .../pattern/Linear2DBlockPattern.java | 6 +- .../pattern/Linear3DBlockPattern.java | 8 +- .../core/function/pattern/NoXPattern.java | 8 +- .../core/function/pattern/NoYPattern.java | 8 +- .../core/function/pattern/NoZPattern.java | 9 +- .../core/function/pattern/OffsetPattern.java | 16 +- .../function/pattern/RandomOffsetPattern.java | 16 +- .../function/pattern/RelativePattern.java | 16 +- .../pattern/SolidRandomOffsetPattern.java | 18 +- .../pattern/SurfaceRandomOffsetPattern.java | 14 +- .../core/function/visitor/AboveVisitor.java | 2 +- .../core/function/visitor/DFSVisitor.java | 6 +- .../function/visitor/DirectionalVisitor.java | 12 +- .../history/RollbackOptimizedHistory.java | 12 +- .../history/changeset/AbstractChangeSet.java | 16 +- .../history/changeset/BlockBagChangeSet.java | 6 +- .../core/math/BlockVector3ChunkMap.java | 2 +- .../core/math/BlockVectorSet.java | 18 +- .../core/math/LocalBlockVectorSet.java | 12 +- .../core/math/heightmap/HeightMap.java | 13 +- .../math/heightmap/RotatableHeightMap.java | 2 +- .../math/heightmap/ScalableHeightMap.java | 16 +- .../math/random/SimplexNoiseGenerator.java | 4 +- .../core/queue/IChunkExtent.java | 14 +- .../core/queue/IChunkGet.java | 2 +- .../core/queue/IChunkSet.java | 2 +- .../core/queue/IQueueExtent.java | 2 +- .../implementation/ParallelQueueExtent.java | 6 +- .../SingleThreadQueueExtent.java | 2 +- .../implementation/blocks/CharSetBlocks.java | 4 +- .../blocks/ThreadUnsafeCharBlocks.java | 2 +- .../preloader/AsyncPreloader.java | 6 +- .../core/regions/FuzzyRegion.java | 4 +- .../core/regions/PolyhedralRegion.java | 18 +- .../core/regions/RegionWrapper.java | 24 +- .../core/regions/Triangle.java | 12 +- .../regions/filter/CuboidRegionFilter.java | 16 +- .../core/util/MainUtil.java | 6 +- .../core/util/WEManager.java | 4 +- .../core/util/collection/BlockSet.java | 6 +- .../core/util/collection/BlockVector3Set.java | 8 +- .../core/util/collection/MemBlockSet.java | 11 +- .../core/world/SimpleWorld.java | 4 +- .../core/wrappers/AsyncPlayer.java | 2 +- .../java/com/sk89q/util/yaml/YAMLNode.java | 20 +- .../java/com/sk89q/worldedit/EditSession.java | 220 +++++++++--------- .../worldedit/command/BrushCommands.java | 8 +- .../worldedit/command/ClipboardCommands.java | 12 +- .../command/FlattenedClipboardTransform.java | 12 +- .../worldedit/command/GenerationCommands.java | 22 +- .../worldedit/command/HistorySubCommands.java | 18 +- .../worldedit/command/RegionCommands.java | 14 +- .../worldedit/command/SelectionCommands.java | 24 +- .../worldedit/command/UtilityCommands.java | 13 +- .../command/argument/OffsetConverter.java | 6 +- .../worldedit/command/tool/BrushTool.java | 2 +- .../command/tool/brush/GravityBrush.java | 8 +- .../command/util/annotation/Confirm.java | 3 +- .../platform/AbstractPlayerActor.java | 8 +- .../com/sk89q/worldedit/extent/Extent.java | 20 +- .../sk89q/worldedit/extent/InputExtent.java | 14 +- .../sk89q/worldedit/extent/OutputExtent.java | 6 +- .../extent/clipboard/BlockArrayClipboard.java | 102 ++++---- .../worldedit/extent/clipboard/Clipboard.java | 28 +-- .../extent/clipboard/io/ClipboardWriter.java | 6 +- .../clipboard/io/SpongeSchematicReader.java | 8 +- .../clipboard/io/SpongeSchematicWriter.java | 24 +- .../extent/inventory/BlockBagExtent.java | 2 +- .../transform/BlockTransformExtent.java | 6 +- .../validation/DataValidatorExtent.java | 4 +- .../extent/world/SideEffectExtent.java | 2 +- .../function/biome/BiomeReplace.java | 2 +- .../function/biome/ExtentBiomeCopy.java | 2 +- .../function/block/SnowSimulator.java | 2 +- .../function/entity/ExtentEntityCopy.java | 12 +- .../function/factory/ApplyLayer.java | 4 +- .../worldedit/function/factory/Deform.java | 6 +- .../function/mask/BoundedHeightMask.java | 2 +- .../function/mask/ExpressionMask.java | 4 +- .../function/mask/ExpressionMask2D.java | 4 +- .../worldedit/function/mask/NoiseFilter.java | 2 +- .../worldedit/function/mask/OffsetMask.java | 2 +- .../worldedit/function/mask/OffsetMask2D.java | 4 +- .../operation/BackwardsExtentBlockCopy.java | 18 +- .../function/operation/ForwardExtentCopy.java | 28 +-- .../function/pattern/RandomPattern.java | 4 +- .../pattern/RepeatingExtentPattern.java | 6 +- .../function/visitor/BreadthFirstSearch.java | 14 +- .../function/visitor/DownwardVisitor.java | 4 +- .../function/visitor/RegionVisitor.java | 8 +- .../history/changeset/ArrayListHistory.java | 2 +- .../internal/anvil/ChunkDeleter.java | 22 +- .../internal/anvil/ChunkDeletionInfo.java | 2 +- .../internal/anvil/RegionAccess.java | 4 +- .../internal/cui/SelectionCylinderEvent.java | 10 +- .../cui/SelectionEllipsoidPointEvent.java | 6 +- .../internal/cui/SelectionPoint2DEvent.java | 16 +- .../internal/cui/SelectionPointEvent.java | 6 +- .../internal/cui/ServerCUIHandler.java | 16 +- .../util/RegionOptimizedVectorSorter.java | 6 +- .../internal/wna/WorldNativeAccess.java | 16 +- .../sk89q/worldedit/math/BlockVector2.java | 2 +- .../sk89q/worldedit/math/BlockVector3.java | 2 +- .../worldedit/math/convolution/HeightMap.java | 30 +-- .../math/convolution/SnowHeightMap.java | 16 +- .../KochanekBartelsInterpolation.java | 8 +- .../math/noise/JLibNoiseGenerator.java | 4 +- .../math/transform/AffineTransform.java | 24 +- .../worldedit/regions/AbstractFlatRegion.java | 4 +- .../worldedit/regions/AbstractRegion.java | 36 ++- .../sk89q/worldedit/regions/CuboidRegion.java | 210 ++++++++--------- .../worldedit/regions/CylinderRegion.java | 26 +-- .../worldedit/regions/EllipsoidRegion.java | 58 ++--- .../worldedit/regions/Polygonal2DRegion.java | 62 ++--- .../com/sk89q/worldedit/regions/Region.java | 18 +- .../worldedit/regions/RegionIntersection.java | 4 +- .../com/sk89q/worldedit/regions/Regions.java | 8 +- .../worldedit/regions/TransformRegion.java | 6 +- .../factory/CylinderRegionFactory.java | 4 +- .../iterator/FlatRegion3DIterator.java | 2 +- .../regions/iterator/FlatRegionIterator.java | 10 +- .../regions/iterator/RegionIterator.java | 16 +- .../ConvexPolyhedralRegionSelector.java | 4 +- .../selector/CylinderRegionSelector.java | 12 +- .../ExtendingCuboidRegionSelector.java | 12 +- .../selector/Polygonal2DRegionSelector.java | 14 +- .../selector/SphereRegionSelector.java | 6 +- .../regions/shape/ArbitraryBiomeShape.java | 18 +- .../regions/shape/ArbitraryShape.java | 18 +- .../com/sk89q/worldedit/util/Direction.java | 14 +- .../com/sk89q/worldedit/util/TargetBlock.java | 12 +- .../sk89q/worldedit/util/TreeGenerator.java | 10 +- .../worldedit/util/collection/BlockMap.java | 12 +- .../util/collection/VectorPositionList.java | 6 +- .../com/sk89q/worldedit/world/NullWorld.java | 2 +- .../worldedit/world/chunk/AnvilChunk.java | 12 +- .../worldedit/world/chunk/AnvilChunk13.java | 10 +- .../worldedit/world/chunk/AnvilChunk15.java | 6 +- .../worldedit/world/chunk/AnvilChunk17.java | 12 +- .../worldedit/world/chunk/AnvilChunk18.java | 14 +- .../sk89q/worldedit/world/chunk/OldChunk.java | 8 +- .../world/snapshot/SnapshotRestore.java | 8 +- .../experimental/SnapshotRestore.java | 8 +- .../worldedit/world/storage/ChunkStore.java | 2 +- .../world/storage/LegacyChunkStore.java | 8 +- .../world/storage/McRegionChunkStore.java | 4 +- .../world/storage/McRegionReader.java | 4 +- .../expression/RealExpressionTest.java | 2 +- .../util/RegionOptimizedVectorSorterTest.java | 10 +- .../sk89q/worldedit/util/LocationTest.java | 32 +-- 244 files changed, 1493 insertions(+), 1515 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java index 22c5a07b2..6d1038677 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java @@ -27,7 +27,6 @@ import com.google.common.collect.Sets; import com.google.common.util.concurrent.Futures; import com.mojang.datafixers.util.Either; import com.mojang.serialization.Lifecycle; -import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.NBTConstants; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; @@ -531,7 +530,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) @@ -581,10 +580,10 @@ public final class PaperweightAdapter implements BukkitImplAdapter>) - getChunkFutureMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) + getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) .thenApply(either -> either.left().orElse(null)) ); } catch (IllegalAccessException | InvocationTargetException e) { @@ -797,7 +796,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter entry : tiles.entrySet()) { final CompoundTag nativeTag = entry.getValue(); final BlockVector3 blockHash = entry.getKey(); - final int x = blockHash.getX() + bx; - final int y = blockHash.getY(); - final int z = blockHash.getZ() + bz; + final int x = blockHash.x() + bx; + final int y = blockHash.y(); + final int z = blockHash.z() + bz; final BlockPos pos = new BlockPos(x, y, z); synchronized (nmsWorld) { diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java index b40c12b1a..6d7e28504 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java @@ -570,7 +570,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) @@ -631,10 +631,10 @@ public final class PaperweightAdapter implements BukkitImplAdapter>) - getChunkFutureMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) + getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) .thenApply(either -> either.left().orElse(null)) ); } catch (IllegalAccessException | InvocationTargetException e) { @@ -848,7 +848,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter entry : tiles.entrySet()) { final CompoundTag nativeTag = entry.getValue(); final BlockVector3 blockHash = entry.getKey(); - final int x = blockHash.getX() + bx; - final int y = blockHash.getY(); - final int z = blockHash.getZ() + bz; + final int x = blockHash.x() + bx; + final int y = blockHash.y(); + final int z = blockHash.z() + bz; final BlockPos pos = new BlockPos(x, y, z); synchronized (nmsWorld) { diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java index b73e6d06e..d8dafb8e5 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java @@ -530,7 +530,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) @@ -580,10 +580,10 @@ public final class PaperweightAdapter implements BukkitImplAdapter>) - getChunkFutureMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) + getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) .thenApply(either -> either.left().orElse(null)) ); } catch (IllegalAccessException | InvocationTargetException e) { @@ -797,7 +797,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter entry : tiles.entrySet()) { final CompoundTag nativeTag = entry.getValue(); final BlockVector3 blockHash = entry.getKey(); - final int x = blockHash.getX() + bx; - final int y = blockHash.getY(); - final int z = blockHash.getZ() + bz; + final int x = blockHash.x() + bx; + final int y = blockHash.y(); + final int z = blockHash.z() + bz; final BlockPos pos = new BlockPos(x, y, z); synchronized (nmsWorld) { diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java index 899c6e0c4..51b97b081 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java @@ -530,7 +530,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) @@ -580,10 +580,10 @@ public final class PaperweightAdapter implements BukkitImplAdapter>) - getChunkFutureMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) + getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) .thenApply(either -> either.left().orElse(null)) ); } catch (IllegalAccessException | InvocationTargetException e) { @@ -797,7 +797,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter entry : tiles.entrySet()) { final CompoundTag nativeTag = entry.getValue(); final BlockVector3 blockHash = entry.getKey(); - final int x = blockHash.getX() + bx; - final int y = blockHash.getY(); - final int z = blockHash.getZ() + bz; + final int x = blockHash.x() + bx; + final int y = blockHash.y(); + final int z = blockHash.z() + bz; final BlockPos pos = new BlockPos(x, y, z); synchronized (nmsWorld) { diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java index e629c4611..8218ec892 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java @@ -577,7 +577,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter>) - getChunkFutureMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) + getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) .thenApply(either -> either.orElse(null)) ); } catch (IllegalAccessException | InvocationTargetException e) { @@ -874,7 +874,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter entry : tiles.entrySet()) { final CompoundTag nativeTag = entry.getValue(); final BlockVector3 blockHash = entry.getKey(); - final int x = blockHash.getX() + bx; - final int y = blockHash.getY(); - final int z = blockHash.getZ() + bz; + final int x = blockHash.x() + bx; + final int y = blockHash.y(); + final int z = blockHash.z() + bz; final BlockPos pos = new BlockPos(x, y, z); synchronized (nmsWorld) { diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IBukkitAdapter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IBukkitAdapter.java index 9792f9344..6ea8cad89 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IBukkitAdapter.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IBukkitAdapter.java @@ -99,7 +99,7 @@ public interface IBukkitAdapter { checkNotNull(position); return new org.bukkit.Location( world, - position.getX(), position.getY(), position.getZ() + position.x(), position.y(), position.z() ); } @@ -119,7 +119,7 @@ public interface IBukkitAdapter { checkNotNull(location); return new org.bukkit.Location( world, - location.getX(), location.getY(), location.getZ(), + location.x(), location.y(), location.z(), location.getYaw(), location.getPitch() ); diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java index 2a006d141..4afbe03a2 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java @@ -354,7 +354,7 @@ public abstract class Regenerator> 4 << 4) - border * 16, - oldMin.getY(), - (oldMin.getZ() >> 4 << 4) - border * 16 + (oldMin.x() >> 4 << 4) - border * 16, + oldMin.y(), + (oldMin.z() >> 4 << 4) - border * 16 ); BlockVector3 oldMax = region.getMaximumPoint(); BlockVector3 newMax = BlockVector3.at( - (oldMax.getX() >> 4 << 4) + (border + 1) * 16 - 1, - oldMax.getY(), - (oldMax.getZ() >> 4 << 4) + (border + 1) * 16 - 1 + (oldMax.x() >> 4 << 4) + (border + 1) * 16 - 1, + oldMax.y(), + (oldMax.z() >> 4 << 4) + (border + 1) * 16 - 1 ); Region adjustedRegion = new CuboidRegion(newMin, newMax); return adjustedRegion.getChunks().stream() .sorted(Comparator - .comparingInt(BlockVector2::getZ) - .thenComparingInt(BlockVector2::getX)) //needed for RegionLimitedWorldAccess - .mapToLong(c -> MathMan.pairInt(c.getX(), c.getZ())) + .comparingInt(BlockVector2::z) + .thenComparingInt(BlockVector2::x)) //needed for RegionLimitedWorldAccess + .mapToLong(c -> MathMan.pairInt(c.x(), c.z())) .toArray(); } diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java index 1043d9a3e..c847a8688 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java @@ -56,7 +56,7 @@ public class WorldGuardFeature extends BukkitMaskManager implements Listener { if (region instanceof ProtectedPolygonalRegion casted) { BlockVector3 max = region.getMaximumPoint(); BlockVector3 min = region.getMinimumPoint(); - return new Polygonal2DRegion(null, casted.getPoints(), min.getBlockY(), max.getBlockY()); + return new Polygonal2DRegion(null, casted.getPoints(), min.y(), max.y()); } return new AdaptedRegion(region); } diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java index 6cf09da28..792f3937e 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java @@ -94,15 +94,15 @@ public class FaweDelegateSchematicHandler { return; } BlockVector3 dimension = schematic.getClipboard().getDimensions(); - final int WIDTH = dimension.getX(); - final int LENGTH = dimension.getZ(); - final int HEIGHT = dimension.getY(); + final int WIDTH = dimension.x(); + final int LENGTH = dimension.z(); + final int HEIGHT = dimension.y(); final int worldHeight = plot.getArea().getMaxGenHeight() - plot.getArea().getMinGenHeight() + 1; // Validate dimensions CuboidRegion region = plot.getLargestRegion(); boolean sizeMismatch = - ((region.getMaximumPoint().getX() - region.getMinimumPoint().getX() + xOffset + 1) < WIDTH) || ( - (region.getMaximumPoint().getZ() - region.getMinimumPoint().getZ() + zOffset + 1) < LENGTH) || (HEIGHT + ((region.getMaximumPoint().x() - region.getMinimumPoint().x() + xOffset + 1) < WIDTH) || ( + (region.getMaximumPoint().z() - region.getMinimumPoint().z() + zOffset + 1) < LENGTH) || (HEIGHT > worldHeight); if (!Settings.Schematics.PASTE_MISMATCHES && sizeMismatch) { if (actor != null) { @@ -111,8 +111,8 @@ public class FaweDelegateSchematicHandler { TaskManager.runTask(whenDone); return; } - if (((region.getMaximumPoint().getX() - region.getMinimumPoint().getX() + xOffset + 1) < WIDTH) || ( - (region.getMaximumPoint().getZ() - region.getMinimumPoint().getZ() + zOffset + 1) < LENGTH) || (HEIGHT + if (((region.getMaximumPoint().x() - region.getMinimumPoint().x() + xOffset + 1) < WIDTH) || ( + (region.getMaximumPoint().z() - region.getMinimumPoint().z() + zOffset + 1) < LENGTH) || (HEIGHT > worldHeight)) { if (whenDone != null) { TaskManager.runTask(whenDone); @@ -141,7 +141,7 @@ public class FaweDelegateSchematicHandler { } else { y_offset_actual = yOffset + pw.getMinBuildHeight() + editSession.getHighestTerrainBlock(region .getMinimumPoint() - .getX() + 1, region.getMinimumPoint().getZ() + 1, pw.getMinGenHeight(), pw.getMaxGenHeight() + .x() + 1, region.getMinimumPoint().z() + 1, pw.getMinGenHeight(), pw.getMaxGenHeight() ); } } @@ -150,7 +150,7 @@ public class FaweDelegateSchematicHandler { } final BlockVector3 to = BlockVector3 - .at(region.getMinimumPoint().getX() + xOffset, y_offset_actual, region.getMinimumPoint().getZ() + zOffset); + .at(region.getMinimumPoint().x() + xOffset, y_offset_actual, region.getMinimumPoint().z() + zOffset); final Clipboard clipboard = schematic.getClipboard(); clipboard.setOrigin(clipboard.getRegion().getMinimumPoint()); clipboard.paste(editSession, to, true, false, true); diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java index e1ac20617..9f0916a4b 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java @@ -159,8 +159,8 @@ public class PlotSquaredFeature extends FaweMaskManager { regions = WEManager.getMask(pp); if (regions.size() == 1) { CuboidRegion region = regions.iterator().next(); - if (region.getMinimumPoint().getX() == Integer.MIN_VALUE - && region.getMaximumPoint().getX() == Integer.MAX_VALUE) { + if (region.getMinimumPoint().x() == Integer.MIN_VALUE + && region.getMaximumPoint().x() == Integer.MAX_VALUE) { regions.clear(); } } 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 41e7e7294..e0a643015 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 @@ -240,7 +240,7 @@ public enum BukkitAdapter { Vector3 position = location; return new org.bukkit.Location( adapt((World) location.getExtent()), - position.getX(), position.getY(), position.getZ(), + position.x(), position.y(), position.z(), location.getYaw(), location.getPitch() ); @@ -258,7 +258,7 @@ public enum BukkitAdapter { checkNotNull(position); return new org.bukkit.Location( world, - position.getX(), position.getY(), position.getZ() + position.x(), position.y(), position.z() ); } @@ -274,7 +274,7 @@ public enum BukkitAdapter { checkNotNull(position); return new org.bukkit.Location( world, - position.getX(), position.getY(), position.getZ() + position.x(), position.y(), position.z() ); } @@ -290,7 +290,7 @@ public enum BukkitAdapter { checkNotNull(location); return new org.bukkit.Location( world, - location.getX(), location.getY(), location.getZ(), + location.x(), location.y(), location.z(), location.getYaw(), location.getPitch() ); 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 9c5196e91..8a0081484 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 @@ -242,9 +242,9 @@ public class BukkitPlayer extends AbstractPlayerActor { //FAWE end return TaskManager.taskManager().sync(() -> player.teleport(new Location( finalWorld, - pos.getX(), - pos.getY(), - pos.getZ(), + pos.x(), + pos.y(), + pos.z(), yaw, pitch ))); @@ -422,7 +422,7 @@ public class BukkitPlayer extends AbstractPlayerActor { @Override public > void sendFakeBlock(BlockVector3 pos, B block) { - Location loc = new Location(player.getWorld(), pos.getX(), pos.getY(), pos.getZ()); + Location loc = new Location(player.getWorld(), pos.x(), pos.y(), pos.z()); if (block == null) { player.sendBlockChange(loc, player.getWorld().getBlockAt(loc).getBlockData()); } else { 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 1598cb547..b2fdeead9 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 @@ -247,7 +247,7 @@ public class BukkitWorld extends AbstractWorld { //FAWE start - safe edit region testCoords(pt); //FAWE end - return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getLightLevel(); + return getWorld().getBlockAt(pt.x(), pt.y(), pt.z()).getLightLevel(); } @Override @@ -284,7 +284,7 @@ public class BukkitWorld extends AbstractWorld { return false; } - Block block = getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + Block block = getWorld().getBlockAt(pt.x(), pt.y(), pt.z()); BlockState state = PaperLib.getBlockState(block, false).getState(); if (!(state instanceof InventoryHolder)) { return false; @@ -363,8 +363,8 @@ public class BukkitWorld extends AbstractWorld { //FAWE end World world = getWorld(); //FAWE start - int X = pt.getBlockX() >> 4; - int Z = pt.getBlockZ() >> 4; + int X = pt.x() >> 4; + int Z = pt.z() >> 4; if (Fawe.isMainThread()) { world.getChunkAt(X, Z); } else if (PaperLib.isPaper()) { @@ -413,7 +413,7 @@ public class BukkitWorld extends AbstractWorld { public void fixAfterFastMode(Iterable chunks) { World world = getWorld(); for (BlockVector2 chunkPos : chunks) { - world.refreshChunk(chunkPos.getBlockX(), chunkPos.getBlockZ()); + world.refreshChunk(chunkPos.x(), chunkPos.z()); } } @@ -495,13 +495,13 @@ public class BukkitWorld extends AbstractWorld { //FAWE start - safe edit region testCoords(pt); //FAWE end - getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).breakNaturally(); + getWorld().getBlockAt(pt.x(), pt.y(), pt.z()).breakNaturally(); } //FAWE start @Override public Collection getBlockDrops(BlockVector3 position) { - return getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()).getDrops().stream() + return getWorld().getBlockAt(position.x(), position.y(), position.z()).getDrops().stream() .map(BukkitAdapter::adapt).collect(Collectors.toList()); } //FAWE end @@ -538,7 +538,7 @@ public class BukkitWorld extends AbstractWorld { } } if (WorldEditPlugin.getInstance().getLocalConfiguration().unsupportedVersionEditing) { - Block bukkitBlock = getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + Block bukkitBlock = getWorld().getBlockAt(position.x(), position.y(), position.z()); return BukkitAdapter.adapt(bukkitBlock.getBlockData()); } else { throw new RuntimeException(new UnsupportedVersionEditException()); @@ -562,7 +562,7 @@ public class BukkitWorld extends AbstractWorld { } } } - Block bukkitBlock = getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + Block bukkitBlock = getWorld().getBlockAt(position.x(), position.y(), position.z()); bukkitBlock.setBlockData(BukkitAdapter.adapt(block), sideEffects.doesApplyAny()); return true; } @@ -584,8 +584,8 @@ public class BukkitWorld extends AbstractWorld { if (!Settings.settings().REGION_RESTRICTIONS_OPTIONS.RESTRICT_TO_SAFE_RANGE) { return; } - int x = position.getX(); - int z = position.getZ(); + int x = position.x(); + int z = position.z(); if (x > 30000000 || z > 30000000 || x < -30000000 || z < -30000000) { throw FaweCache.OUTSIDE_SAFE_REGION; } @@ -636,9 +636,9 @@ public class BukkitWorld extends AbstractWorld { testCoords(position); //FAWE end if (HAS_3D_BIOMES) { - return BukkitAdapter.adapt(getWorld().getBiome(position.getBlockX(), position.getBlockY(), position.getBlockZ())); + return BukkitAdapter.adapt(getWorld().getBiome(position.x(), position.y(), position.z())); } else { - return BukkitAdapter.adapt(getWorld().getBiome(position.getBlockX(), position.getBlockZ())); + return BukkitAdapter.adapt(getWorld().getBiome(position.x(), position.z())); } } @@ -649,9 +649,9 @@ public class BukkitWorld extends AbstractWorld { testCoords(position); //FAWE end if (HAS_3D_BIOMES) { - getWorld().setBiome(position.getBlockX(), position.getBlockY(), position.getBlockZ(), BukkitAdapter.adapt(biome)); + getWorld().setBiome(position.x(), position.y(), position.z(), BukkitAdapter.adapt(biome)); } else { - getWorld().setBiome(position.getBlockX(), position.getBlockZ(), BukkitAdapter.adapt(biome)); + getWorld().setBiome(position.x(), position.z(), BukkitAdapter.adapt(biome)); } return true; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java index 4c5339017..acc0d8bf3 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java @@ -339,11 +339,11 @@ public class FaweAPI { final BlockVector3 bot = selection.getMinimumPoint(); final BlockVector3 top = selection.getMaximumPoint(); - final int minX = bot.getBlockX() >> 4; - final int minZ = bot.getBlockZ() >> 4; + final int minX = bot.x() >> 4; + final int minZ = bot.z() >> 4; - final int maxX = top.getBlockX() >> 4; - final int maxZ = top.getBlockZ() >> 4; + final int maxX = top.x() >> 4; + final int maxZ = top.z() >> 4; int count = 0; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/BlendBall.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/BlendBall.java index 902e48a9b..ec3e0766e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/BlendBall.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/BlendBall.java @@ -50,9 +50,9 @@ public class BlendBall implements Brush { final int outsetSize = (int) (size + 1); double brushSizeSquared = size * size; - int tx = position.getBlockX(); - int ty = position.getBlockY(); - int tz = position.getBlockZ(); + int tx = position.x(); + int ty = position.y(); + int tz = position.z(); int[] frequency = new int[BlockTypes.size()]; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CatenaryBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CatenaryBrush.java index e380e74b0..7ad15cef4 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CatenaryBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CatenaryBrush.java @@ -81,9 +81,9 @@ public class CatenaryBrush implements Brush, ResettableTool { return pos1.add(pos2).divide(2).toBlockPoint(); } double curveLen = pos1.distance(pos2) * lenPercent; - double dy = pos2.getY() - pos1.getY(); - double dx = pos2.getX() - pos1.getX(); - double dz = pos2.getZ() - pos1.getZ(); + double dy = pos2.y() - pos1.y(); + double dx = pos2.x() - pos1.x(); + double dz = pos2.z() - pos1.z(); double dh = Math.sqrt(dx * dx + dz * dz); double g = Math.sqrt(curveLen * curveLen - dy * dy) / 2; double a = 0.00001; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CommandBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CommandBrush.java index 227960c1d..b71578b55 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CommandBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CommandBrush.java @@ -54,9 +54,9 @@ public class CommandBrush implements Brush { position.subtract(radius, radius, radius), position.add(radius, radius, radius) ); - String replaced = command.replace("{x}", Integer.toString(position.getBlockX())) - .replace("{y}", Integer.toString(position.getBlockY())) - .replace("{z}", Integer.toString(position.getBlockZ())) + String replaced = command.replace("{x}", Integer.toString(position.x())) + .replace("{y}", Integer.toString(position.y())) + .replace("{z}", Integer.toString(position.z())) .replace("{world}", editSession.getWorld().getName()) .replace("{size}", Integer.toString(radius)); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CopyPastaBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CopyPastaBrush.java index 4aeb2daeb..b635c1e7d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CopyPastaBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CopyPastaBrush.java @@ -65,11 +65,11 @@ public class CopyPastaBrush implements Brush, ResettableTool { mask = Masks.alwaysTrue(); } final ResizableClipboardBuilder builder = new ResizableClipboardBuilder(editSession.getWorld()); - final int minY = position.getBlockY(); + final int minY = position.y(); mask = new AbstractDelegateMask(mask) { @Override public boolean test(BlockVector3 vector) { - if (super.test(vector) && vector.getBlockY() >= minY) { + if (super.test(vector) && vector.y() >= minY) { BaseBlock block = editSession.getFullBlock(vector); if (!block.getBlockType().getMaterial().isAir()) { builder.add(vector, BlockTypes.AIR.getDefaultState().toBaseBlock(), block); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ErodeBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ErodeBrush.java index 21879751c..da52bf504 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ErodeBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ErodeBrush.java @@ -63,9 +63,9 @@ public class ErodeBrush implements Brush { Clipboard buffer1 = new CPUOptimizedClipboard(region); Clipboard buffer2 = new CPUOptimizedClipboard(region); - final int bx = target.getBlockX(); - final int by = target.getBlockY(); - final int bz = target.getBlockZ(); + final int bx = target.x(); + final int by = target.y(); + final int bz = target.z(); for (int x = -brushSize, relx = 0; x <= brushSize && relx < buffer1.getWidth(); x++, relx++) { int x0 = x + bx; @@ -106,7 +106,7 @@ public class ErodeBrush implements Brush { for (BlockVector3 pos : finalBuffer) { BlockState block = pos.getBlock(finalBuffer); - es.setBlock(pos.getX() + bx - brushSize, pos.getY() + by - brushSize, pos.getZ() + bz - brushSize, block); + es.setBlock(pos.x() + bx - brushSize, pos.y() + by - brushSize, pos.z() + bz - brushSize, block); } } @@ -139,9 +139,9 @@ public class ErodeBrush implements Brush { int highest = 1; for (BlockVector3 offs : FACES_TO_CHECK) { BaseBlock next = current.getFullBlock( - relx + offs.getBlockX(), - rely + offs.getBlockY(), - relz + offs.getBlockZ() + relx + offs.x(), + rely + offs.y(), + relz + offs.z() ); if (!next.getBlockType().getMaterial().isMovementBlocker()) { continue; @@ -190,9 +190,9 @@ public class ErodeBrush implements Brush { int total = 0; for (BlockVector3 offs : FACES_TO_CHECK) { BaseBlock next = current.getFullBlock( - relx + offs.getBlockX(), - rely + offs.getBlockY(), - relz + offs.getBlockZ() + relx + offs.x(), + rely + offs.y(), + relz + offs.z() ); if (next.getMaterial().isMovementBlocker()) { continue; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/FallingSphere.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/FallingSphere.java index fd720c54e..d54bbebb6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/FallingSphere.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/FallingSphere.java @@ -12,9 +12,9 @@ public class FallingSphere implements Brush { @Override public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { - int px = position.getBlockX(); - int py = position.getBlockY(); - int pz = position.getBlockZ(); + int px = position.x(); + int py = position.y(); + int pz = position.z(); int maxY = editSession.getMaxY(); int minY = editSession.getMinY(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/InspectBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/InspectBrush.java index 5ad9b818a..1ef2a27fa 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/InspectBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/InspectBrush.java @@ -14,7 +14,6 @@ import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; -import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.util.Location; @@ -25,7 +24,6 @@ import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockState; -import org.apache.logging.log4j.Logger; import java.io.IOException; import java.util.Iterator; @@ -80,9 +78,9 @@ public class InspectBrush extends BrushTool { return true; } BlockVector3 target = targetVector.toBlockPoint(); - final int x = target.getBlockX(); - final int y = target.getBlockY(); - final int z = target.getBlockZ(); + final int x = target.x(); + final int y = target.y(); + final int z = target.z(); World world = player.getWorld(); RollbackDatabase db = DBHandler.dbHandler().getDatabase(world); int count = 0; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/RecurseBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/RecurseBrush.java index 869d45150..f87fee30e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/RecurseBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/RecurseBrush.java @@ -35,7 +35,7 @@ public record RecurseBrush(boolean dfs) implements Brush { DFSRecursiveVisitor visitor = new DFSRecursiveVisitor(mask, replace, Integer.MAX_VALUE, Integer.MAX_VALUE) { @Override public boolean isVisitable(BlockVector3 from, BlockVector3 to) { - int y = to.getBlockY(); + int y = to.y(); return y < maxY && radMask.test(to) && super.isVisitable(from, to); } }; @@ -45,7 +45,7 @@ public record RecurseBrush(boolean dfs) implements Brush { RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, radius, editSession.getMinY(), editSession.getMaxY()) { @Override public boolean isVisitable(BlockVector3 from, BlockVector3 to) { - int y = to.getBlockY(); + int y = to.y(); return y < maxY && super.isVisitable(from, to); } }; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/RockBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/RockBrush.java index 4196a7e11..27937b836 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/RockBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/RockBrush.java @@ -19,15 +19,15 @@ public record RockBrush(double amplitude, double frequency, Vector3 radius) impl double seedY = ThreadLocalRandom.current().nextDouble(); double seedZ = ThreadLocalRandom.current().nextDouble(); - int px = position.getBlockX(); - int py = position.getBlockY(); - int pz = position.getBlockZ(); + int px = position.x(); + int py = position.y(); + int pz = position.z(); double distort = this.frequency / size; - double modX = 1D / radius.getX(); - double modY = 1D / radius.getY(); - double modZ = 1D / radius.getZ(); + double modX = 1D / radius.x(); + double modY = 1D / radius.y(); + double modZ = 1D / radius.z(); int radiusSqr = (int) (size * size); int sizeInt = (int) size * 2; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterBrush.java index e14d0c599..26cf07558 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterBrush.java @@ -67,15 +67,15 @@ public class ScatterBrush implements Brush { } BlockVector3 patternSize = pattern.size(); BlockVector3Set placed = BlockVector3Set.getAppropriateVectorSet(patternSize.add(distance, distance, distance)); - placed.setOffset(position.getX(), position.getY(), position.getZ()); + placed.setOffset(position.x(), position.y(), position.z()); int maxFails = 1000; for (int i = 0; i < count; i++) { int index = ThreadLocalRandom.current().nextInt(length); BlockVector3 pos = visited.get(index); if (pos != null && canApply(pos)) { - int x = pos.getBlockX(); - int y = pos.getBlockY(); - int z = pos.getBlockZ(); + int x = pos.x(); + int y = pos.y(); + int z = pos.z(); if (placed.containsRadius(x, y, z, distance)) { if (maxFails-- <= 0) { break; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterCommand.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterCommand.java index 1d7841355..9e2c16555 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterCommand.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterCommand.java @@ -45,9 +45,9 @@ public class ScatterCommand extends ScatterBrush { position.subtract(radius, radius, radius), position.add(radius, radius, radius) ); - String replaced = command.replace("{x}", Integer.toString(position.getBlockX())) - .replace("{y}", Integer.toString(position.getBlockY())) - .replace("{z}", Integer.toString(position.getBlockZ())) + String replaced = command.replace("{x}", Integer.toString(position.x())) + .replace("{y}", Integer.toString(position.y())) + .replace("{z}", Integer.toString(position.z())) .replace("{world}", editSession.getWorld().getName()) .replace("{size}", Integer.toString(radius)); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterOverlayBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterOverlayBrush.java index cd7ce9aaa..d6a991234 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterOverlayBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ScatterOverlayBrush.java @@ -16,9 +16,9 @@ public class ScatterOverlayBrush extends ScatterBrush { @Override public void apply(EditSession editSession, LocalBlockVectorSet placed, BlockVector3 pt, Pattern p, double size) throws MaxChangedBlocksException { - final int x = pt.getBlockX(); - final int y = pt.getBlockY(); - final int z = pt.getBlockZ(); + final int x = pt.x(); + final int y = pt.y(); + final int z = pt.z(); BlockVector3 dir = getDirection(pt); if (dir == null) { getDir: @@ -37,7 +37,7 @@ public class ScatterOverlayBrush extends ScatterBrush { return; } } - editSession.setBlock(x + dir.getBlockX(), y + dir.getBlockY(), z + dir.getBlockZ(), p); + editSession.setBlock(x + dir.x(), y + dir.y(), z + dir.z(), p); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ShatterBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ShatterBrush.java index 41b36e12c..196b71f50 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ShatterBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ShatterBrush.java @@ -80,13 +80,13 @@ public class ShatterBrush extends ScatterBrush { } for (int i1 = 0; i1 < BreadthFirstSearch.DIAGONAL_DIRECTIONS.length; i1++) { BlockVector3 direction = BreadthFirstSearch.DIAGONAL_DIRECTIONS[i1]; - int x2 = x + direction.getBlockX(); - int y2 = y + direction.getBlockY(); - int z2 = z + direction.getBlockZ(); + int x2 = x + direction.x(); + int y2 = y + direction.y(); + int z2 = z + direction.z(); // Check boundary - int dx = position.getBlockX() - x2; - int dy = position.getBlockY() - y2; - int dz = position.getBlockZ() - z2; + int dx = position.x() - x2; + int dy = position.y() - y2; + int dz = position.z() - z2; int dSqr = (dx * dx) + (dy * dy) + (dz * dz); if (dSqr <= radius2) { BlockVector3 bv = mutable.setComponents(x2, y2, z2); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/SplineBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/SplineBrush.java index 55d8fd96a..e1fa38708 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/SplineBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/SplineBrush.java @@ -130,9 +130,9 @@ public class SplineBrush implements Brush, ResettableTool { private Vector3 getCentroid(Collection points) { MutableVector3 sum = new MutableVector3(); for (BlockVector3 p : points) { - sum.mutX(sum.getX() + p.getX()); - sum.mutY(sum.getY() + p.getY()); - sum.mutZ(sum.getZ() + p.getZ()); + sum.mutX(sum.x() + p.x()); + sum.mutY(sum.y() + p.y()); + sum.mutZ(sum.z() + p.z()); } return sum.multiply(1.0 / points.size()); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/SurfaceSpline.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/SurfaceSpline.java index f652c4f94..8c94e76ad 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/SurfaceSpline.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/SurfaceSpline.java @@ -38,16 +38,16 @@ public class SurfaceSpline implements Brush { int minY = editSession.getMinY(); if (path.isEmpty() || !pos.equals(path.get(path.size() - 1))) { int max = editSession.getNearestSurfaceTerrainBlock( - pos.getBlockX(), - pos.getBlockZ(), - pos.getBlockY(), + pos.x(), + pos.z(), + pos.y(), minY, maxY ); if (max == -1) { return; } - path.add(BlockVector3.at(pos.getBlockX(), max, pos.getBlockZ())); + path.add(BlockVector3.at(pos.x(), max, pos.z())); if (editSession.getActor() != null) { editSession.getActor().print(Caption.of("fawe.worldedit.brush.spline.primary.2")); } @@ -69,9 +69,9 @@ public class SurfaceSpline implements Brush { LocalBlockVectorSet vset = new LocalBlockVectorSet(); for (double loop = 0; loop <= 1; loop += 1D / splinelength / quality) { final Vector3 tipv = interpol.getPosition(loop); - final int tipx = MathMan.roundInt(tipv.getX()); - final int tipz = (int) tipv.getZ(); - int tipy = MathMan.roundInt(tipv.getY()); + final int tipx = MathMan.roundInt(tipv.x()); + final int tipz = (int) tipv.z(); + int tipy = MathMan.roundInt(tipv.y()); tipy = editSession.getNearestSurfaceTerrainBlock(tipx, tipz, tipy, minY, maxY, Integer.MIN_VALUE, Integer.MAX_VALUE); if (tipy == Integer.MIN_VALUE || tipy == Integer.MAX_VALUE) { continue; @@ -88,15 +88,15 @@ public class SurfaceSpline implements Brush { LocalBlockVectorSet newSet = new LocalBlockVectorSet(); final int ceilrad = (int) Math.ceil(radius); for (BlockVector3 v : vset) { - final int tipx = v.getBlockX(); - final int tipz = v.getBlockZ(); + final int tipx = v.x(); + final int tipz = v.z(); for (int loopx = tipx - ceilrad; loopx <= tipx + ceilrad; loopx++) { for (int loopz = tipz - ceilrad; loopz <= tipz + ceilrad; loopz++) { if (MathMan.hypot2(loopx - tipx, 0, loopz - tipz) <= radius2) { int y = editSession.getNearestSurfaceTerrainBlock( loopx, loopz, - v.getBlockY(), + v.y(), minY, maxY, Integer.MIN_VALUE, diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/sweep/ClipboardSpline.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/sweep/ClipboardSpline.java index 87f1495f5..281c78c74 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/sweep/ClipboardSpline.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/sweep/ClipboardSpline.java @@ -83,7 +83,7 @@ public class ClipboardSpline extends Spline { Region region = clipboard.getRegion(); BlockVector3 origin = clipboard.getOrigin(); // center = region.getCenter().setY(origin.getY() - 1); - center = region.getCenter().withY(origin.getY() - 1).toBlockPoint(); + center = region.getCenter().withY(origin.y() - 1).toBlockPoint(); this.centerOffset = center.subtract(center.round()); this.center = center.subtract(centerOffset); this.transform = transform; @@ -108,15 +108,15 @@ public class ClipboardSpline extends Spline { clipboardHolder.setTransform(transform); BlockVector3 functionOffset = target.subtract(clipboard.getOrigin()); - final int offX = functionOffset.getBlockX(); - final int offY = functionOffset.getBlockY(); - final int offZ = functionOffset.getBlockZ(); + final int offX = functionOffset.x(); + final int offY = functionOffset.y(); + final int offZ = functionOffset.z(); Operation operation = clipboardHolder .createPaste(editSession) .to(target) .ignoreAirBlocks(true) - .filter(v -> buffer.add(v.getBlockX() + offX, v.getBlockY() + offY, v.getBlockZ() + offZ)) + .filter(v -> buffer.add(v.x() + offX, v.y() + offY, v.z() + offZ)) .build(); Operations.completeLegacy(operation); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/sweep/Spline.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/sweep/Spline.java index 945c10f5a..872ec495e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/sweep/Spline.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/sweep/Spline.java @@ -121,7 +121,7 @@ public abstract class Spline { * 2 dimensional "cross" product. cross2D(v1, v2) = |v1|*|v2|*sin(theta) or v1 X v2 taking Y to be 0 */ private double cross2D(Vector2 v1, Vector2 v2) { - return v1.getX() * v2.getZ() - v2.getX() * v1.getZ(); + return v1.x() * v2.z() - v2.x() * v1.z(); } /** @@ -144,7 +144,7 @@ public abstract class Spline { // Calculate rotation from spline Vector3 deriv = interpolation.get1stDerivative(position); - Vector2 deriv2D = Vector2.at(deriv.getX(), deriv.getZ()).normalize(); + Vector2 deriv2D = Vector2.at(deriv.x(), deriv.z()).normalize(); double angle = Math.toDegrees( -Math.atan2(cross2D(direction, deriv2D), direction.dot(deriv2D)) ); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/sweep/SweepBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/sweep/SweepBrush.java index fa4bb971c..603fb4302 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/sweep/SweepBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/sweep/SweepBrush.java @@ -79,13 +79,13 @@ public class SweepBrush implements Brush, ResettableTool { Clipboard clipboard = holder.getClipboard(); BlockVector3 dimensions = clipboard.getDimensions(); - double quality = Math.max(dimensions.getBlockX(), dimensions.getBlockZ()); + double quality = Math.max(dimensions.x(), dimensions.z()); AffineTransform transform = new AffineTransform(); ClipboardSpline spline = new ClipboardSpline(editSession, holder, interpol, transform, nodes.size()); - if (dimensions.getBlockX() > dimensions.getBlockZ()) { + if (dimensions.x() > dimensions.z()) { spline.setDirection(Vector2.at(0, 1)); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java index 1677521fe..f8207f2dc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java @@ -179,13 +179,13 @@ public class RollbackDatabase extends AsyncNotifyQueue { } try (PreparedStatement stmt = connection.prepareStatement(stmtStr.formatted(this.prefix))) { stmt.setInt(1, (int) (minTime / 1000)); - stmt.setInt(2, pos1.getBlockX()); - stmt.setInt(3, pos2.getBlockX()); - stmt.setInt(4, pos1.getBlockZ()); - stmt.setInt(5, pos2.getBlockZ()); + stmt.setInt(2, pos1.x()); + stmt.setInt(3, pos2.x()); + stmt.setInt(4, pos1.z()); + stmt.setInt(5, pos2.z()); // Keep 128 offset for backwards-compatibility - stmt.setInt(6, pos1.getBlockY() - 128); - stmt.setInt(7, pos2.getBlockY() - 128); + stmt.setInt(6, pos1.y() - 128); + stmt.setInt(7, pos2.y() - 128); if (uuid != null) { byte[] uuidBytes = toBytes(uuid); stmt.setBytes(8, uuidBytes); @@ -210,13 +210,13 @@ public class RollbackDatabase extends AsyncNotifyQueue { .array(); stmt.setBytes(1, uuidBytes); stmt.setInt(2, (int) (minTime / 1000)); - stmt.setInt(3, pos1.getBlockX()); - stmt.setInt(4, pos2.getBlockX()); - stmt.setInt(5, pos1.getBlockZ()); - stmt.setInt(6, pos2.getBlockZ()); + stmt.setInt(3, pos1.x()); + stmt.setInt(4, pos2.x()); + stmt.setInt(5, pos1.z()); + stmt.setInt(6, pos2.z()); // Keep 128 offset for backwards-compatibility - stmt.setInt(7, pos1.getBlockY() - 128); - stmt.setInt(8, pos2.getBlockY() - 128); + stmt.setInt(7, pos1.y() - 128); + stmt.setInt(8, pos2.y() - 128); } } return count; @@ -262,13 +262,13 @@ public class RollbackDatabase extends AsyncNotifyQueue { BlockVector3 pos1 = change.getMinimumPoint(); BlockVector3 pos2 = change.getMaximumPoint(); - stmt.setInt(4, pos1.getX()); - stmt.setInt(5, pos2.getX()); - stmt.setInt(6, pos1.getZ()); - stmt.setInt(7, pos2.getZ()); + stmt.setInt(4, pos1.x()); + stmt.setInt(5, pos2.x()); + stmt.setInt(6, pos1.z()); + stmt.setInt(7, pos2.z()); // Keep 128 offset for backwards-compatibility - stmt.setInt(8, pos1.getY() - 128); - stmt.setInt(9, pos2.getY() - 128); + stmt.setInt(8, pos1.y() - 128); + stmt.setInt(9, pos2.y() - 128); stmt.setString(10, change.getCommand()); stmt.setInt(11, change.size()); stmt.executeUpdate(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/BlockTranslateExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/BlockTranslateExtent.java index d7b8a986e..7f84be430 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/BlockTranslateExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/BlockTranslateExtent.java @@ -24,7 +24,7 @@ public class BlockTranslateExtent extends AbstractDelegateExtent { @Override public > boolean setBlock(BlockVector3 location, T block) throws WorldEditException { - return getExtent().setBlock(location.getX() + dx, location.getY() + dy, location.getZ() + dz, block); + return getExtent().setBlock(location.x() + dx, location.y() + dy, location.z() + dz, block); } @Override @@ -49,7 +49,7 @@ public class BlockTranslateExtent extends AbstractDelegateExtent { @Override public BlockState getBlock(BlockVector3 location) { - return getBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + return getBlock(location.x(), location.y(), location.z()); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java index 84044f9b2..103dd8824 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java @@ -64,11 +64,11 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc @Override public final boolean contains(BlockVector3 p) { - return contains(p.getBlockX(), p.getBlockY(), p.getBlockZ()); + return contains(p.x(), p.y(), p.z()); } public final boolean contains(BlockVector2 p) { - return contains(p.getBlockX(), p.getBlockZ()); + return contains(p.x(), p.z()); } @Override @@ -96,7 +96,7 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc @Override public BiomeType getBiome(BlockVector3 position) { - return getBiomeType(position.getX(), position.getY(), position.getZ()); + return getBiomeType(position.x(), position.y(), position.z()); } @Override @@ -112,7 +112,7 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc @Override public BaseBlock getFullBlock(BlockVector3 position) { - return getFullBlock(position.getX(), position.getY(), position.getZ()); + return getFullBlock(position.x(), position.y(), position.z()); } @Override @@ -128,7 +128,7 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc @Override public BlockState getBlock(BlockVector3 position) { - return getBlock(position.getX(), position.getY(), position.getZ()); + return getBlock(position.x(), position.y(), position.z()); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java index 2fc5133c6..d85594215 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java @@ -66,7 +66,7 @@ public class HistoryExtent extends AbstractDelegateExtent { @Override public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { - return setBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ(), block); + return setBlock(location.x(), location.y(), location.z(), block); } @Nullable @@ -111,7 +111,7 @@ public class HistoryExtent extends AbstractDelegateExtent { public boolean setBiome(BlockVector3 position, BiomeType newBiome) { BiomeType oldBiome = this.getBiome(position); if (!oldBiome.getId().equals(newBiome.getId())) { - this.changeSet.addBiomeChange(position.getBlockX(), position.getBlockY(), position.getBlockZ(), oldBiome, newBiome); + this.changeSet.addBiomeChange(position.x(), position.y(), position.z(), oldBiome, newBiome); return getExtent().setBiome(position, newBiome); } else { return false; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java index 24d440c57..d02ff9320 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java @@ -373,12 +373,12 @@ public class LimitExtent extends AbstractDelegateExtent { size = ((Collection) positions).size(); } else if (positions instanceof Region) { BlockVector3 dim = ((Region) positions).getDimensions(); - size = dim.getX() * dim.getY() * dim.getZ(); + size = dim.x() * dim.y() * dim.z(); } else if (positions instanceof Extent) { BlockVector3 min = ((Extent) positions).getMinimumPoint(); BlockVector3 max = ((Extent) positions).getMinimumPoint(); BlockVector3 dim = max.subtract(min).add(BlockVector3.ONE); - size = dim.getX() * dim.getY() * dim.getZ(); + size = dim.x() * dim.y() * dim.z(); } else { ExtentFilterBlock block = new ExtentFilterBlock(this); for (BlockVector3 pos : positions) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PositionTransformExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PositionTransformExtent.java index 6d74acc16..d5e8e57e8 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PositionTransformExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PositionTransformExtent.java @@ -38,9 +38,9 @@ public class PositionTransformExtent extends ResettableExtent { if (min == null) { min = pos; } - mutable.mutX(pos.getX() - min.getX()); - mutable.mutY(pos.getY() - min.getY()); - mutable.mutZ(pos.getZ() - min.getZ()); + mutable.mutX(pos.x() - min.x()); + mutable.mutY(pos.y() - min.y()); + mutable.mutZ(pos.z() - min.z()); MutableVector3 tmp = new MutableVector3(transform.apply(mutable.toVector3())); return min.add(tmp.roundHalfUp().toBlockPoint()); } @@ -49,9 +49,9 @@ public class PositionTransformExtent extends ResettableExtent { if (min == null) { min = BlockVector3.at(x, y, z); } - mutable.mutX(x - min.getX()); - mutable.mutY(y - min.getY()); - mutable.mutZ(z - min.getZ()); + mutable.mutX(x - min.x()); + mutable.mutY(y - min.y()); + mutable.mutZ(z - min.z()); MutableVector3 tmp = new MutableVector3(transform.apply(mutable.toVector3())); return min.add(tmp.roundHalfUp().toBlockPoint()); } @@ -73,10 +73,10 @@ public class PositionTransformExtent extends ResettableExtent { @Override public BiomeType getBiome(BlockVector3 position) { - mutable.mutX(position.getBlockX()); - mutable.mutZ(position.getBlockZ()); - mutable.mutY(position.getBlockY()); - return super.getBiome(getPos(mutable.getX(), mutable.getY(), mutable.getZ())); + mutable.mutX(position.x()); + mutable.mutZ(position.z()); + mutable.mutY(position.y()); + return super.getBiome(getPos(mutable.x(), mutable.y(), mutable.z())); } @Override @@ -92,10 +92,10 @@ public class PositionTransformExtent extends ResettableExtent { @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { - mutable.mutX(position.getBlockX()); - mutable.mutZ(position.getBlockZ()); - mutable.mutY(position.getBlockY()); - return super.setBiome(getPos(mutable.getX(), mutable.getY(), mutable.getZ()), biome); + mutable.mutX(position.x()); + mutable.mutZ(position.z()); + mutable.mutY(position.y()); + return super.setBiome(getPos(mutable.x(), mutable.y(), mutable.z()), biome); } public void setTransform(Transform transform) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ProcessedWEExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ProcessedWEExtent.java index 5abe90348..e08e1535f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ProcessedWEExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ProcessedWEExtent.java @@ -80,12 +80,12 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { @Override public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { - return setBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ(), block); + return setBlock(location.x(), location.y(), location.z(), block); } @Override public BlockState getBlock(BlockVector3 location) { - return getBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + return getBlock(location.x(), location.y(), location.z()); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SourceMaskExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SourceMaskExtent.java index 6c2230372..6da0a2ac6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SourceMaskExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SourceMaskExtent.java @@ -41,8 +41,8 @@ public class SourceMaskExtent extends TemporalExtent { @Override public > boolean setBlock(BlockVector3 location, T block) throws WorldEditException { - set(location.getBlockX(), location.getBlockY(), location.getBlockZ(), block); - return mask.test(location) && super.setBlock(location.getX(), location.getY(), location.getZ(), block); + set(location.x(), location.y(), location.z(), block); + return mask.test(location) && super.setBlock(location.x(), location.y(), location.z(), block); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TemporalExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TemporalExtent.java index ac36bef5a..ff0fa5106 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TemporalExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TemporalExtent.java @@ -44,7 +44,7 @@ public class TemporalExtent extends PassthroughExtent { @Override public BlockState getBlock(BlockVector3 position) { - if (position.getX() == x && position.getY() == y && position.getZ() == z) { + if (position.x() == x && position.y() == y && position.z() == z) { return block.toImmutableState(); } return super.getBlock(position); @@ -60,7 +60,7 @@ public class TemporalExtent extends PassthroughExtent { @Override public BaseBlock getFullBlock(BlockVector3 position) { - if (position.getX() == x && position.getY() == y && position.getZ() == z) { + if (position.x() == x && position.y() == y && position.z() == z) { if (block instanceof BaseBlock) { return (BaseBlock) block; } else { @@ -72,7 +72,7 @@ public class TemporalExtent extends PassthroughExtent { @Override public BiomeType getBiome(BlockVector3 position) { - if (position.getX() == bx && position.getZ() == bz) { + if (position.x() == bx && position.z() == bz) { return biome; } return super.getBiome(position); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java index 250227439..c424c0f8c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java @@ -55,13 +55,13 @@ public class TransformExtent extends BlockTransformExtent { if (min == null) { min = pos; } - mutable1.mutX(pos.getX() - min.getX()); - mutable1.mutY(pos.getY() - min.getY()); - mutable1.mutZ(pos.getZ() - min.getZ()); + mutable1.mutX(pos.x() - min.x()); + mutable1.mutY(pos.y() - min.y()); + mutable1.mutZ(pos.z() - min.z()); Vector3 tmp = getTransform().apply(mutable1); - mutable2.mutX(tmp.getX() + min.getX()); - mutable2.mutY(tmp.getY() + min.getY()); - mutable2.mutZ(tmp.getZ() + min.getZ()); + mutable2.mutX(tmp.x() + min.x()); + mutable2.mutY(tmp.y() + min.y()); + mutable2.mutZ(tmp.z() + min.z()); return mutable2; } @@ -69,20 +69,20 @@ public class TransformExtent extends BlockTransformExtent { if (min == null) { min = BlockVector3.at(x, y, z); } - mutable1.mutX(x - min.getX()); - mutable1.mutY(y - min.getY()); - mutable1.mutZ(z - min.getZ()); + mutable1.mutX(x - min.x()); + mutable1.mutY(y - min.y()); + mutable1.mutZ(z - min.z()); Vector3 tmp = getTransform().apply(mutable1); - mutable2.mutX(tmp.getX() + min.getX()); - mutable2.mutY(tmp.getY() + min.getY()); - mutable2.mutZ(tmp.getZ() + min.getZ()); + mutable2.mutX(tmp.x() + min.x()); + mutable2.mutY(tmp.y() + min.y()); + mutable2.mutZ(tmp.z() + min.z()); return tmp.toBlockPoint(); } @Override public BlockState getBlock(int x, int y, int z) { BlockVector3 p = getPos(x, y, z); - return transform(super.getBlock(p.getX(), p.getY(), p.getZ())); + return transform(super.getBlock(p.x(), p.y(), p.z())); } @Override @@ -93,7 +93,7 @@ public class TransformExtent extends BlockTransformExtent { @Override public BiomeType getBiomeType(int x, int y, int z) { BlockVector3 p = getPos(x, y, z); - return super.getBiomeType(p.getX(), y, p.getZ()); + return super.getBiomeType(p.x(), y, p.z()); } @Override @@ -114,7 +114,7 @@ public class TransformExtent extends BlockTransformExtent { @Override public boolean setBiome(int x, int y, int z, BiomeType biome) { BlockVector3 p = getPos(x, y, z); - return super.setBiome(p.getX(), p.getY(), p.getZ(), biome); + return super.setBiome(p.x(), p.y(), p.z(), biome); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java index 1a30a0df8..6a306fc44 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java @@ -41,7 +41,7 @@ public class CPUOptimizedClipboard extends LinearClipboard { @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { - return setBiome(position.getX(), position.getY(), position.getZ(), biome); + return setBiome(position.x(), position.y(), position.z(), biome); } @Override @@ -92,7 +92,7 @@ public class CPUOptimizedClipboard extends LinearClipboard { @Override public BiomeType getBiome(BlockVector3 position) { - return getBiome(getBiomeIndex(position.getX(), position.getY(), position.getZ())); + return getBiome(getBiomeIndex(position.x(), position.y(), position.z())); } public void convertTilesToIndex() { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java index 76f22a194..f42cdbbff 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java @@ -359,7 +359,7 @@ public class DiskOptimizedClipboard extends LinearClipboard { @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { - return setBiome(position.getX(), position.getY(), position.getZ(), biome); + return setBiome(position.x(), position.y(), position.z(), biome); } @Override @@ -417,7 +417,7 @@ public class DiskOptimizedClipboard extends LinearClipboard { @Override public BiomeType getBiome(BlockVector3 position) { - return getBiome(getBiomeIndex(position.getX(), position.getY(), position.getZ())); + return getBiome(getBiomeIndex(position.x(), position.y(), position.z())); } public BlockArrayClipboard toClipboard() { @@ -438,9 +438,9 @@ public class DiskOptimizedClipboard extends LinearClipboard { super.setOrigin(origin); origin = origin.subtract(offset); try { - byteBuffer.putShort(10, (short) origin.getBlockX()); - byteBuffer.putShort(12, (short) origin.getBlockY()); - byteBuffer.putShort(14, (short) origin.getBlockZ()); + byteBuffer.putShort(10, (short) origin.x()); + byteBuffer.putShort(12, (short) origin.y()); + byteBuffer.putShort(14, (short) origin.z()); } catch (Throwable e) { e.printStackTrace(); } @@ -450,9 +450,9 @@ public class DiskOptimizedClipboard extends LinearClipboard { protected void setOffset(BlockVector3 offset) { super.setOffset(offset); try { - byteBuffer.putShort(16, (short) offset.getBlockX()); - byteBuffer.putShort(18, (short) offset.getBlockY()); - byteBuffer.putShort(20, (short) offset.getBlockZ()); + byteBuffer.putShort(16, (short) offset.x()); + byteBuffer.putShort(18, (short) offset.y()); + byteBuffer.putShort(20, (short) offset.z()); } catch (Throwable e) { e.printStackTrace(); } @@ -588,9 +588,9 @@ public class DiskOptimizedClipboard extends LinearClipboard { CompoundTag data = entity.getState().getNbtData(); HashMap value = new HashMap<>(data.getValue()); List pos = new ArrayList<>(3); - pos.add(new DoubleTag(entity.getLocation().getX())); - pos.add(new DoubleTag(entity.getLocation().getX())); - pos.add(new DoubleTag(entity.getLocation().getX())); + pos.add(new DoubleTag(entity.getLocation().x())); + pos.add(new DoubleTag(entity.getLocation().x())); + pos.add(new DoubleTag(entity.getLocation().x())); value.put("Pos", new ListTag(DoubleTag.class, pos)); nbtOS.writeTag(new CompoundTag(value)); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java index 449795e5d..6c7a910f2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java @@ -64,7 +64,7 @@ public class MemoryOptimizedClipboard extends LinearClipboard { @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { - return setBiome(position.getX(), position.getY(), position.getZ(), biome); + return setBiome(position.x(), position.y(), position.z(), biome); } @Override @@ -115,7 +115,7 @@ public class MemoryOptimizedClipboard extends LinearClipboard { @Override public BiomeType getBiome(BlockVector3 position) { - return getBiome(getBiomeIndex(position.getX(), position.getY(), position.getZ())); + return getBiome(getBiomeIndex(position.x(), position.y(), position.z())); } private int getOrdinal(int index) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/SimpleClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/SimpleClipboard.java index c01abd787..f902f6007 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/SimpleClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/SimpleClipboard.java @@ -70,17 +70,17 @@ public abstract class SimpleClipboard implements Clipboard { @Override public final int getWidth() { - return size.getBlockX(); + return size.x(); } @Override public final int getHeight() { - return size.getBlockY(); + return size.y(); } @Override public final int getLength() { - return size.getBlockZ(); + return size.z(); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/WorldCopyClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/WorldCopyClipboard.java index cdd4ae8df..4bb50ca73 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/WorldCopyClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/WorldCopyClipboard.java @@ -56,7 +56,7 @@ public class WorldCopyClipboard extends ReadOnlyClipboard { @Override public BiomeType getBiome(BlockVector3 position) { - return getExtent().getBiomeType(position.getX(), position.getY(), position.getZ()); + return getExtent().getBiomeType(position.x(), position.y(), position.z()); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java index d884e0151..156e38544 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java @@ -396,8 +396,8 @@ public class FastSchematicReader extends NBTSchematicReader { int locY = loc.getBlockY(); int locZ = loc.getBlockZ(); BlockVector3 max = min.add(dimensions).subtract(BlockVector3.ONE); - if (locX < min.getX() || locY < min.getY() || locZ < min.getZ() - || locX > max.getX() || locY > max.getY() || locZ > max.getZ()) { + if (locX < min.x() || locY < min.y() || locZ < min.z() + || locX > max.x() || locY > max.y() || locZ > max.z()) { for (Entity e : clipboard.getEntities()) { clipboard.removeEntity(e); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java index db3452d29..5218b1c1e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java @@ -114,15 +114,15 @@ public class FastSchematicWriter implements ClipboardWriter { // The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin' out.writeNamedTag("Offset", new int[]{ - min.getBlockX(), - min.getBlockY(), - min.getBlockZ(), + min.x(), + min.y(), + min.z(), }); out.writeLazyCompoundTag("Metadata", out1 -> { - out1.writeNamedTag("WEOffsetX", offset.getBlockX()); - out1.writeNamedTag("WEOffsetY", offset.getBlockY()); - out1.writeNamedTag("WEOffsetZ", offset.getBlockZ()); + out1.writeNamedTag("WEOffsetX", offset.x()); + out1.writeNamedTag("WEOffsetY", offset.y()); + out1.writeNamedTag("WEOffsetZ", offset.z()); out1.writeNamedTag("FAWEVersion", Fawe.instance().getVersion().build); }); @@ -162,9 +162,9 @@ public class FastSchematicWriter implements ClipboardWriter { // Dum. values.remove("id"); values.put("Pos", new IntArrayTag(new int[]{ - pos.getX(), - pos.getY(), - pos.getZ() + pos.x(), + pos.y(), + pos.z() })); numTiles++; @@ -282,10 +282,10 @@ public class FastSchematicWriter implements ClipboardWriter { int length = clipboard.getRegion().getLength(); MutableBlockVector3 mutable = new MutableBlockVector3(); for (int z = 0, i = 0; z < length; z++) { - int z0 = min.getBlockZ() + z; + int z0 = min.z() + z; for (int x = 0; x < width; x++, i++) { - int x0 = min.getBlockX() + x; - BiomeType biome = clipboard.getBiome(mutable.setComponents(x0, min.getY(), z0)); + int x0 = min.x() + x; + BiomeType biome = clipboard.getBiome(mutable.setComponents(x0, min.y(), z0)); task.applyInt(i, biome.getInternalId()); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java index 66deefeb7..d52d74b5a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java @@ -213,8 +213,8 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { if (block.getBlockType() != BlockTypes.STRUCTURE_VOID) { int combined = block.getInternalId(); int index = indexes.get(combined); - List pos = Arrays.asList(point.getX() - min.getX(), - point.getY() - min.getY(), point.getZ() - min.getZ() + List pos = Arrays.asList(point.x() - min.x(), + point.y() - min.y(), point.z() - min.z() ); if (!block.hasNbtData()) { blocks.add(FaweCache.INSTANCE.asMap("state", index, "pos", pos)); @@ -231,7 +231,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { ArrayList> entities = new ArrayList<>(); for (Entity entity : clipboard.getEntities()) { Location loc = entity.getLocation(); - List pos = Arrays.asList(loc.getX(), loc.getY(), loc.getZ()); + List pos = Arrays.asList(loc.x(), loc.y(), loc.z()); List blockPos = Arrays.asList(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); BaseEntity state = entity.getState(); if (state != null) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/PNGWriter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/PNGWriter.java index b5cbc7fb2..48a3315d5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/PNGWriter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/PNGWriter.java @@ -75,9 +75,9 @@ public class PNGWriter implements ClipboardWriter { MutableBlockVector3 mutableLeft = new MutableBlockVector3(0, 0, 0); BlockVector3 min = clipboard.getMinimumPoint(); - int y0 = min.getBlockY(); - int z0 = min.getBlockZ(); - int x0 = min.getBlockX(); + int y0 = min.y(); + int z0 = min.z(); + int x0 = min.x(); for (int x = x0; x < x0 + width; x++) { mutable.mutX(x); mutableTop.mutX(x); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/ArrayImageMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/ArrayImageMask.java index 4976af5f7..07c9acac1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/ArrayImageMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/ArrayImageMask.java @@ -20,7 +20,7 @@ public class ArrayImageMask implements FilterBlockMask { @Override public boolean applyBlock(FilterBlock block) { - int height = image.getRGB(block.getX(), block.getZ()) & 0xFF; + int height = image.getRGB(block.x(), block.z()) & 0xFF; return height == 255 || height > 0 && !white && random.nextInt(256) <= height; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/AbstractSingleFilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/AbstractSingleFilterBlock.java index 95e50dc76..5d64ead7c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/AbstractSingleFilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/AbstractSingleFilterBlock.java @@ -83,18 +83,18 @@ public abstract class AbstractSingleFilterBlock extends FilterBlock { @Override public BlockVector3 getMinimumPoint() { - return at(getX(), getY(), getZ()); + return at(x(), y(), z()); } @Override public BlockVector3 getMaximumPoint() { - return at(getX(), getY(), getZ()); + return at(x(), y(), z()); } @Override public > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { - if (x == this.getX() && y == this.getY() && z == this.getZ()) { + if (x == this.x() && y == this.y() && z == this.z()) { setFullBlock(block.toBaseBlock()); return true; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/EntityInBlockRemovingProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/EntityInBlockRemovingProcessor.java index 58baf8633..693356a7a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/EntityInBlockRemovingProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/EntityInBlockRemovingProcessor.java @@ -30,9 +30,9 @@ public class EntityInBlockRemovingProcessor implements IBatchProcessor { continue; } BlockVector3 pos = tag.getEntityPosition().toBlockPoint(); - int x = pos.getX() & 15; - int y = pos.getY(); - int z = pos.getZ() & 15; + int x = pos.x() & 15; + int y = pos.y(); + int z = pos.z() & 15; if (!set.hasSection(y >> 4)) { continue; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/NMSRelighter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/NMSRelighter.java index e38df12f5..dbe717e49 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/NMSRelighter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/NMSRelighter.java @@ -273,9 +273,9 @@ public class NMSRelighter implements Relighter { int lightLevel = (int) val[1]; this.computeRemoveBlockLight( - node.getX() - 1, - node.getY(), - node.getZ(), + node.x() - 1, + node.y(), + node.z(), lightLevel, lightRemovalQueue, lightPropagationQueue, @@ -283,20 +283,20 @@ public class NMSRelighter implements Relighter { visited ); this.computeRemoveBlockLight( - node.getX() + 1, - node.getY(), - node.getZ(), + node.x() + 1, + node.y(), + node.z(), lightLevel, lightRemovalQueue, lightPropagationQueue, removalVisited, visited ); - if (node.getY() > minY) { + if (node.y() > minY) { this.computeRemoveBlockLight( - node.getX(), - node.getY() - 1, - node.getZ(), + node.x(), + node.y() - 1, + node.z(), lightLevel, lightRemovalQueue, lightPropagationQueue, @@ -304,11 +304,11 @@ public class NMSRelighter implements Relighter { visited ); } - if (node.getY() < maxY) { + if (node.y() < maxY) { this.computeRemoveBlockLight( - node.getX(), - node.getY() + 1, - node.getZ(), + node.x(), + node.y() + 1, + node.z(), lightLevel, lightRemovalQueue, lightPropagationQueue, @@ -317,9 +317,9 @@ public class NMSRelighter implements Relighter { ); } this.computeRemoveBlockLight( - node.getX(), - node.getY(), - node.getZ() - 1, + node.x(), + node.y(), + node.z() - 1, lightLevel, lightRemovalQueue, lightPropagationQueue, @@ -327,9 +327,9 @@ public class NMSRelighter implements Relighter { visited ); this.computeRemoveBlockLight( - node.getX(), - node.getY(), - node.getZ() + 1, + node.x(), + node.y(), + node.z() + 1, lightLevel, lightRemovalQueue, lightPropagationQueue, @@ -340,27 +340,27 @@ public class NMSRelighter implements Relighter { while (!lightPropagationQueue.isEmpty()) { MutableBlockVector3 node = lightPropagationQueue.poll(); - ChunkHolder iChunk = (ChunkHolder) queue.getOrCreateChunk(node.getX() >> 4, node.getZ() >> 4); + ChunkHolder iChunk = (ChunkHolder) queue.getOrCreateChunk(node.x() >> 4, node.z() >> 4); if (!iChunk.isInit()) { - iChunk.init(queue, node.getX() >> 4, node.getZ() >> 4); + iChunk.init(queue, node.x() >> 4, node.z() >> 4); } - int lightLevel = iChunk.getEmittedLight(node.getX() & 15, node.getY(), node.getZ() & 15); - BlockState state = this.queue.getBlock(node.getX(), node.getY(), node.getZ()); + int lightLevel = iChunk.getEmittedLight(node.x() & 15, node.y(), node.z() & 15); + BlockState state = this.queue.getBlock(node.x(), node.y(), node.z()); String id = state.getBlockType().getId().toLowerCase(Locale.ROOT); if (lightLevel <= 1) { continue; } if (id.contains("slab")) { boolean top = state.getState(slabHalf).equalsIgnoreCase("top"); - computeSlab(node.getX(), node.getY(), node.getZ(), lightLevel, lightPropagationQueue, visited, top); + computeSlab(node.x(), node.y(), node.z(), lightLevel, lightPropagationQueue, visited, top); } else if (id.contains("stair")) { boolean top = state.getState(stairHalf).equalsIgnoreCase("top"); Direction direction = getStairDir(state); String shape = getStairShape(state); computeStair( - node.getX(), - node.getY(), - node.getZ(), + node.x(), + node.y(), + node.z(), lightLevel, lightPropagationQueue, visited, @@ -369,7 +369,7 @@ public class NMSRelighter implements Relighter { shape ); } else { - computeNormal(node.getX(), node.getY(), node.getZ(), lightLevel, lightPropagationQueue, visited); + computeNormal(node.x(), node.y(), node.z(), lightLevel, lightPropagationQueue, visited); } } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/OffsetTransform.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/OffsetTransform.java index a8ade6df1..c2536deca 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/OffsetTransform.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/OffsetTransform.java @@ -30,9 +30,9 @@ public class OffsetTransform extends ResettableExtent { @Override public boolean setBiome(BlockVector3 location, BiomeType biome) { - int x = location.getX() + dx; - int y = location.getX() + dy; - int z = location.getX() + dz; + int x = location.x() + dx; + int y = location.x() + dy; + int z = location.x() + dz; if (!getExtent().contains(x, y, z)) { return false; } @@ -53,9 +53,9 @@ public class OffsetTransform extends ResettableExtent { @Override public > boolean setBlock(BlockVector3 location, T block) throws WorldEditException { - int x = location.getX() + dx; - int y = location.getX() + dy; - int z = location.getX() + dz; + int x = location.x() + dx; + int y = location.x() + dy; + int z = location.x() + dz; if (!getExtent().contains(x, y, z)) { return false; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/RandomOffsetTransform.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/RandomOffsetTransform.java index 268255bf2..4ad3189c7 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/RandomOffsetTransform.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/RandomOffsetTransform.java @@ -34,9 +34,9 @@ public class RandomOffsetTransform extends ResettableExtent { @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { - int x = position.getBlockX() + random.nextInt(1 + (dx << 1)) - dx; - int y = position.getBlockY() + random.nextInt(1 + (dy << 1)) - dy; - int z = position.getBlockZ() + random.nextInt(1 + (dz << 1)) - dz; + int x = position.x() + random.nextInt(1 + (dx << 1)) - dx; + int y = position.y() + random.nextInt(1 + (dy << 1)) - dy; + int z = position.z() + random.nextInt(1 + (dz << 1)) - dz; if (!getExtent().contains(x, y, z)) { return false; } @@ -57,9 +57,9 @@ public class RandomOffsetTransform extends ResettableExtent { @Override public > boolean setBlock(BlockVector3 pos, T block) throws WorldEditException { - int x = pos.getBlockX() + random.nextInt(1 + (dx << 1)) - dx; - int y = pos.getBlockY() + random.nextInt(1 + (dy << 1)) - dy; - int z = pos.getBlockZ() + random.nextInt(1 + (dz << 1)) - dz; + int x = pos.x() + random.nextInt(1 + (dx << 1)) - dx; + int y = pos.y() + random.nextInt(1 + (dy << 1)) - dy; + int z = pos.z() + random.nextInt(1 + (dz << 1)) - dz; if (!getExtent().contains(x, y, z)) { return false; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/ScaleTransform.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/ScaleTransform.java index 29af87055..c81d123df 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/ScaleTransform.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/ScaleTransform.java @@ -55,9 +55,9 @@ public class ScaleTransform extends ResettableExtent { if (min == null) { min = pos; } - mutable.mutX(min.getX() + (pos.getX() - min.getX()) * dx); - mutable.mutY(min.getY() + (pos.getY() - min.getY()) * dy); - mutable.mutZ(min.getZ() + (pos.getZ() - min.getZ()) * dz); + mutable.mutX(min.x() + (pos.x() - min.x()) * dx); + mutable.mutY(min.y() + (pos.y() - min.y()) * dy); + mutable.mutZ(min.z() + (pos.z() - min.z()) * dz); return new MutableVector3(mutable); } @@ -65,9 +65,9 @@ public class ScaleTransform extends ResettableExtent { if (min == null) { min = BlockVector3.at(x, y, z); } - mutable.mutX(min.getX() + (x - min.getX()) * dx); - mutable.mutY(min.getY() + (y - min.getY()) * dy); - mutable.mutZ(min.getZ() + (z - min.getZ()) * dz); + mutable.mutX(min.x() + (x - min.x()) * dx); + mutable.mutY(min.y() + (y - min.y()) * dy); + mutable.mutZ(min.z() + (z - min.z()) * dz); return new MutableVector3(mutable); } @@ -77,15 +77,15 @@ public class ScaleTransform extends ResettableExtent { boolean result = false; MutableVector3 vector3 = getPos(location); MutableBlockVector3 pos = new MutableBlockVector3(); - double sx = vector3.getX(); - double sy = vector3.getY(); - double sz = vector3.getZ(); + double sx = vector3.x(); + double sy = vector3.y(); + double sz = vector3.z(); double ex = sx + dx; double ey = Math.max(minY, Math.min(maxy, sy + dy)); double ez = sz + dz; - for (pos.mutY(sy); pos.getY() < ey; pos.mutY(pos.getY() + 1)) { - for (pos.mutZ(sz); pos.getZ() < ez; pos.mutZ(pos.getZ() + 1)) { - for (pos.mutX(sx); pos.getX() < ex; pos.mutX(pos.getX() + 1)) { + for (pos.mutY(sy); pos.y() < ey; pos.mutY(pos.y() + 1)) { + for (pos.mutZ(sz); pos.z() < ez; pos.mutZ(pos.z() + 1)) { + for (pos.mutX(sx); pos.x() < ex; pos.mutX(pos.x() + 1)) { if (!getExtent().contains(pos)) { continue; } @@ -101,15 +101,15 @@ public class ScaleTransform extends ResettableExtent { boolean result = false; MutableVector3 vector3 = getPos(position); MutableBlockVector3 pos = new MutableBlockVector3(); - double sx = vector3.getX(); - double sy = vector3.getY(); - double sz = vector3.getZ(); + double sx = vector3.x(); + double sy = vector3.y(); + double sz = vector3.z(); double ex = sx + dx; double ey = Math.max(minY, Math.min(maxy, sy + dy)); double ez = sz + dz; - for (pos.mutY(sy); pos.getY() < ey; pos.mutY(pos.getY() + 1)) { - for (pos.mutZ(sz); pos.getZ() < ez; pos.mutZ(pos.getZ() + 1)) { - for (pos.mutX(sx); pos.getX() < ex; pos.mutX(pos.getX() + 1)) { + for (pos.mutY(sy); pos.y() < ey; pos.mutY(pos.y() + 1)) { + for (pos.mutZ(sz); pos.z() < ez; pos.mutZ(pos.z() + 1)) { + for (pos.mutX(sx); pos.x() < ex; pos.mutX(pos.x() + 1)) { if (!getExtent().contains(pos)) { continue; } @@ -126,15 +126,15 @@ public class ScaleTransform extends ResettableExtent { boolean result = false; MutableVector3 vector3 = getPos(x1, y1, z1); MutableBlockVector3 pos = new MutableBlockVector3(); - double sx = vector3.getX(); - double sy = vector3.getY(); - double sz = vector3.getZ(); - double ex = vector3.getX() + dx; + double sx = vector3.x(); + double sy = vector3.y(); + double sz = vector3.z(); + double ex = vector3.x() + dx; double ey = Math.min(maxy, sy + dy); - double ez = vector3.getZ() + dz; - for (pos.mutY(sy); pos.getY() < ey; pos.mutY(pos.getY() + 1)) { - for (pos.mutZ(sz); pos.getZ() < ez; pos.mutZ(pos.getZ() + 1)) { - for (pos.mutX(sx); pos.getX() < ex; pos.mutX(pos.getX() + 1)) { + double ez = vector3.z() + dz; + for (pos.mutY(sy); pos.y() < ey; pos.mutY(pos.y() + 1)) { + for (pos.mutZ(sz); pos.z() < ez; pos.mutZ(pos.z() + 1)) { + for (pos.mutX(sx); pos.x() < ex; pos.mutX(pos.x() + 1)) { if (!getExtent().contains(pos)) { continue; } @@ -150,15 +150,15 @@ public class ScaleTransform extends ResettableExtent { boolean result = false; MutableVector3 vector3 = getPos(x1, y1, z1); MutableBlockVector3 pos = new MutableBlockVector3(); - double sx = vector3.getX(); - double sy = vector3.getY(); - double sz = vector3.getZ(); + double sx = vector3.x(); + double sy = vector3.y(); + double sz = vector3.z(); double ex = sx + dx; double ey = Math.max(minY, Math.min(maxy, sy + dy)); double ez = sz + dz; - for (pos.mutY(sy); pos.getY() < ey; pos.mutY(pos.getY() + 1)) { - for (pos.mutZ(sz); pos.getZ() < ez; pos.mutZ(pos.getZ() + 1)) { - for (pos.mutX(sx); pos.getX() < ex; pos.mutX(pos.getX() + 1)) { + for (pos.mutY(sy); pos.y() < ey; pos.mutY(pos.y() + 1)) { + for (pos.mutZ(sz); pos.z() < ez; pos.mutZ(pos.z() + 1)) { + for (pos.mutX(sx); pos.x() < ex; pos.mutX(pos.x() + 1)) { if (!getExtent().contains(pos)) { continue; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/SelectTransform.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/SelectTransform.java index 57f77b2fe..b3be0a43a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/SelectTransform.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/SelectTransform.java @@ -27,11 +27,11 @@ public abstract class SelectTransform extends ResettableExtent { public abstract AbstractDelegateExtent getExtent(int x, int z); public Extent getExtent(BlockVector3 pos) { - return getExtent(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); + return getExtent(pos.x(), pos.y(), pos.z()); } public Extent getExtent(BlockVector2 pos) { - return getExtent(pos.getBlockX(), pos.getBlockZ()); + return getExtent(pos.x(), pos.z()); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/SurfaceRegionFunction.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/SurfaceRegionFunction.java index 5f946c933..a6b9ace56 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/SurfaceRegionFunction.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/SurfaceRegionFunction.java @@ -26,8 +26,8 @@ public class SurfaceRegionFunction implements FlatRegionFunction { @Override public boolean apply(BlockVector2 position) throws WorldEditException { - int x = position.getBlockX(); - int z = position.getBlockZ(); + int x = position.x(); + int z = position.z(); int layer = extent.getNearestSurfaceTerrainBlock(x, z, lastY, minY, maxY, false); if (layer != -1) { lastY = layer; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/block/BiomeCopy.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/block/BiomeCopy.java index 3926c19a6..457fff477 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/block/BiomeCopy.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/block/BiomeCopy.java @@ -21,11 +21,11 @@ public class BiomeCopy implements RegionFunction { @Override public boolean apply(BlockVector3 position) throws WorldEditException { - int x = position.getBlockX(); - int y = position.getBlockY(); - int z = position.getBlockZ(); - if (x != mutableVector.getBlockX() || z != mutableVector.getBlockZ() || y != mutableVector - .getBlockY()) { + int x = position.x(); + int y = position.y(); + int z = position.z(); + if (x != mutableVector.x() || z != mutableVector.z() || y != mutableVector + .y()) { mutableVector.setComponents(x, y, z); return destination.setBiome(mutableVector, source.getBiome(mutableVector)); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/CavesGen.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/CavesGen.java index 28bfa0a4c..b9a403f27 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/CavesGen.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/CavesGen.java @@ -72,8 +72,8 @@ public class CavesGen extends GenBase { int maxAngle, double paramDouble4 ) throws WorldEditException { - int bx = chunkPos.getBlockX() << 4; - int bz = chunkPos.getBlockZ() << 4; + int bx = chunkPos.x() << 4; + int bz = chunkPos.z() << 4; double real_x = bx + 7; double real_z = bz + 7; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/GenBase.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/GenBase.java index af1a4e66e..f0637d127 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/GenBase.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/GenBase.java @@ -26,8 +26,8 @@ public abstract class GenBase { public void generate(BlockVector2 chunkPos, Extent chunk) throws WorldEditException { int i = this.checkAreaSize; - int chunkX = chunkPos.getBlockX(); - int chunkZ = chunkPos.getBlockZ(); + int chunkX = chunkPos.x(); + int chunkZ = chunkPos.z(); for (int x = chunkX - i; x <= chunkX + i; x++) { for (int z = chunkZ - i; z <= chunkZ + i; z++) { generateChunk(x, z, chunkPos, chunk); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/SchemGen.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/SchemGen.java index 1ced63f19..250914c05 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/SchemGen.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/SchemGen.java @@ -36,7 +36,7 @@ public class SchemGen implements Resource { int y = extent.getNearestSurfaceTerrainBlock( x, z, - mutable.getBlockY(), + mutable.y(), this.extent.getMinY(), this.extent.getMaxY(), Integer.MIN_VALUE, diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AdjacentAnyMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AdjacentAnyMask.java index 39bb0c41d..956daf67d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AdjacentAnyMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AdjacentAnyMask.java @@ -44,9 +44,9 @@ public class AdjacentAnyMask extends AbstractMask implements ResettableMask { } public BlockVector3 direction(BlockVector3 v) { - int x = v.getBlockX(); - int y = v.getBlockY(); - int z = v.getBlockZ(); + int x = v.x(); + int y = v.y(); + int z = v.z(); if (mask.test(mutable.setComponents(x + 1, y, z))) { return mutable.setComponents(1, 0, 0); } else if (mask.test(mutable.setComponents(x - 1, y, z))) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AdjacentMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AdjacentMask.java index 23065ea7b..981492e0e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AdjacentMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AdjacentMask.java @@ -22,9 +22,9 @@ public class AdjacentMask extends AbstractMask { @Override public boolean test(BlockVector3 bv) { vector.setComponents(bv); - double x = bv.getX(); - double y = bv.getY(); - double z = bv.getZ(); + double x = bv.x(); + double y = bv.y(); + double z = bv.z(); vector.mutX(x + 1); int count = 0; if (mask.test(vector) && ++count == min && max >= 8) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AngleMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AngleMask.java index 52de762ae..01cf15708 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AngleMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AngleMask.java @@ -127,9 +127,9 @@ public class AngleMask extends AbstractExtentMask implements ResettableMask { } private boolean adjacentAir(Extent extent, MutableBlockVector3 mutable) { - int x = mutable.getBlockX(); - int y = mutable.getBlockY(); - int z = mutable.getBlockZ(); + int x = mutable.x(); + int y = mutable.y(); + int z = mutable.z(); if (!mask.test(extent, mutable.setComponents(x + 1, y, z))) { return true; } @@ -154,23 +154,23 @@ public class AngleMask extends AbstractExtentMask implements ResettableMask { if (!mask.test(vector)) { return false; } - int y = vector.getBlockY(); + int y = vector.y(); if (overlay) { MutableBlockVector3 mutable = new MutableBlockVector3(vector); if (y < maxY && !adjacentAir(null, mutable)) { return false; } } - int x = vector.getBlockX(); - int z = vector.getBlockZ(); + int x = vector.x(); + int z = vector.z(); return testSlope(getExtent(), x, y, z); } @Override public boolean test(final Extent extent, final BlockVector3 vector) { - int x = vector.getBlockX(); - int y = vector.getBlockY(); - int z = vector.getBlockZ(); + int x = vector.x(); + int y = vector.y(); + int z = vector.z(); if ((lastX == (lastX = x) & lastZ == (lastZ = z))) { int height = getHeight(extent, x, y, z); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/CachedMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/CachedMask.java index 27e4b9961..5bb757eb2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/CachedMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/CachedMask.java @@ -60,9 +60,9 @@ public class CachedMask extends AbstractDelegateMask implements ResettableMask { @Override public boolean test(BlockVector3 vector) { - int x = vector.getX(); - int y = vector.getY(); - int z = vector.getZ(); + int x = vector.x(); + int y = vector.y(); + int z = vector.z(); try { boolean check = cache_checked.add(x, y, z); if (!check) { @@ -88,9 +88,9 @@ public class CachedMask extends AbstractDelegateMask implements ResettableMask { if (!hasExtent || !(extent instanceof AbstractExtentMask)) { return test(vector); } - int x = vector.getX(); - int y = vector.getY(); - int z = vector.getZ(); + int x = vector.x(); + int y = vector.y(); + int z = vector.z(); AbstractExtentMask mask = (AbstractExtentMask) getMask(); try { boolean check = cache_checked.add(x, y, z); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ImageBrushMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ImageBrushMask.java index ec31337de..d8ff64a76 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ImageBrushMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ImageBrushMask.java @@ -62,17 +62,17 @@ public class ImageBrushMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { if (solid.test(vector)) { - int dx = vector.getBlockX() - center.getBlockX(); - int dy = vector.getBlockY() - center.getBlockY(); - int dz = vector.getBlockZ() - center.getBlockZ(); + int dx = vector.x() - center.x(); + int dy = vector.y() - center.y(); + int dz = vector.z() - center.z(); Vector3 pos1 = transform.apply(mutable.setComponents(dx - 0.5, dy - 0.5, dz - 0.5)); - int x1 = (int) (pos1.getX() * scale + centerImageX); - int z1 = (int) (pos1.getZ() * scale + centerImageZ); + int x1 = (int) (pos1.x() * scale + centerImageX); + int z1 = (int) (pos1.z() * scale + centerImageZ); Vector3 pos2 = transform.apply(mutable.setComponents(dx + 0.5, dy + 0.5, dz + 0.5)); - int x2 = (int) (pos2.getX() * scale + centerImageX); - int z2 = (int) (pos2.getZ() * scale + centerImageZ); + int x2 = (int) (pos2.x() * scale + centerImageX); + int z2 = (int) (pos2.z() * scale + centerImageZ); if (x2 < x1) { int tmp = x1; x1 = x2; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/LayerBrushMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/LayerBrushMask.java index 825039ed0..7f30ab64a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/LayerBrushMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/LayerBrushMask.java @@ -40,20 +40,20 @@ public class LayerBrushMask extends AbstractExtentMask { BlockState previous2 = layers[depth - 2]; for (BlockVector3 dir : BreadthFirstSearch.DEFAULT_DIRECTIONS) { mutable.setComponents( - pos.getBlockX() + dir.getBlockX(), - pos.getBlockY() + dir.getBlockY(), - pos.getBlockZ() + dir.getBlockZ() + pos.x() + dir.x(), + pos.y() + dir.y(), + pos.z() + dir.z() ); if (visitor.isVisited(mutable) && editSession.getBlock( - mutable.getBlockX(), - mutable.getBlockY(), - mutable.getBlockZ() + mutable.x(), + mutable.y(), + mutable.z() ) == previous) { - mutable.setComponents(pos.getBlockX() + dir.getBlockX() * 2, pos.getBlockY() + dir.getBlockY() * 2, - pos.getBlockZ() + dir.getBlockZ() * 2 + mutable.setComponents(pos.x() + dir.x() * 2, pos.y() + dir.y() * 2, + pos.z() + dir.z() * 2 ); if (visitor.isVisited(mutable) - && editSession.getBlock(mutable.getBlockX(), mutable.getBlockY(), mutable.getBlockZ()) == previous2) { + && editSession.getBlock(mutable.x(), mutable.y(), mutable.z()) == previous2) { found = true; break; } else { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/PlaneMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/PlaneMask.java index 6b8b1e4a1..5de393940 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/PlaneMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/PlaneMask.java @@ -15,9 +15,9 @@ public class PlaneMask extends AbstractMask implements ResettableMask { public boolean test(BlockVector3 vector) { switch (mode) { case -1: - originX = vector.getBlockX(); - originY = vector.getBlockY(); - originZ = vector.getBlockZ(); + originX = vector.x(); + originY = vector.y(); + originZ = vector.z(); mode = 0; return true; case 0: @@ -25,13 +25,13 @@ public class PlaneMask extends AbstractMask implements ResettableMask { case 2: case 4: int original = mode; - if (originX != vector.getBlockX()) { + if (originX != vector.x()) { mode &= 1; } - if (originY != vector.getBlockY()) { + if (originY != vector.y()) { mode &= 2; } - if (originZ != vector.getBlockZ()) { + if (originZ != vector.z()) { mode &= 4; } if (Integer.bitCount(mode) >= 3) { @@ -39,13 +39,13 @@ public class PlaneMask extends AbstractMask implements ResettableMask { return false; } default: - if (originX != vector.getBlockX() && (mode & 1) == 0) { + if (originX != vector.x() && (mode & 1) == 0) { return false; } - if (originZ != vector.getBlockZ() && (mode & 4) == 0) { + if (originZ != vector.z() && (mode & 4) == 0) { return false; } - return originY == vector.getBlockY() || (mode & 2) != 0; + return originY == vector.y() || (mode & 2) != 0; } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/RadiusMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/RadiusMask.java index b99e56ddc..c8893ae79 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/RadiusMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/RadiusMask.java @@ -30,17 +30,17 @@ public class RadiusMask extends AbstractMask implements ResettableMask { if (pos == null) { pos = to.toImmutable(); } - int dx = pos.getBlockX() - to.getBlockX(); + int dx = pos.x() - to.x(); int d = dx * dx; if (d > maxSqr) { return false; } - int dz = pos.getBlockZ() - to.getBlockZ(); + int dz = pos.z() - to.z(); d += dz * dz; if (d > maxSqr) { return false; } - int dy = pos.getBlockY() - to.getBlockY(); + int dy = pos.y() - to.y(); d += dy * dy; return d >= minSqr && d <= maxSqr; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SimplexMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SimplexMask.java index d337cd61a..a56238918 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SimplexMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SimplexMask.java @@ -19,7 +19,7 @@ public class SimplexMask extends AbstractMask { @Override public boolean test(BlockVector3 vector) { - double value = SimplexNoise.noise(vector.getBlockX() * scale, vector.getBlockY() * scale, vector.getBlockZ() * scale); + double value = SimplexNoise.noise(vector.x() * scale, vector.y() * scale, vector.z() * scale); return value >= min && value <= max; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/StencilBrushMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/StencilBrushMask.java index 3100f6a9e..25ee249d8 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/StencilBrushMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/StencilBrushMask.java @@ -64,13 +64,13 @@ public class StencilBrushMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { if (solid.test(vector)) { - int dx = vector.getBlockX() - center.getBlockX(); - int dy = vector.getBlockY() - center.getBlockY(); - int dz = vector.getBlockZ() - center.getBlockZ(); + int dx = vector.x() - center.x(); + int dy = vector.y() - center.y(); + int dz = vector.z() - center.z(); Vector3 srcPos = transform.apply(mutable.setComponents(dx, dy, dz)); - dx = MathMan.roundInt(srcPos.getX()); - dz = MathMan.roundInt(srcPos.getZ()); + dx = MathMan.roundInt(srcPos.x()); + dz = MathMan.roundInt(srcPos.z()); int distance = dx * dx + dz * dz; if (distance > size2 || Math.abs(dx) > 256 || Math.abs(dz) > 256) { @@ -83,7 +83,7 @@ public class StencilBrushMask extends AbstractExtentMask { return true; } if (val >= 255 || ThreadLocalRandom.current().nextInt(maxY) < val) { - editSession.setBlock(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ(), pattern); + editSession.setBlock(vector.x(), vector.y(), vector.z(), pattern); } return true; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SurfaceAngleMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SurfaceAngleMask.java index ce42a2d7e..15b347dbc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SurfaceAngleMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SurfaceAngleMask.java @@ -24,7 +24,7 @@ public class SurfaceAngleMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { if (!vector.getBlock(getExtent()).isAir() && nextToAir(vector)) { - double angle = 1 - getAverageAirDirection(vector.toVector3(), size).getY(); + double angle = 1 - getAverageAirDirection(vector.toVector3(), size).y(); return (angle >= (min / 90.0) && angle <= (max / 90.0)); } return false; @@ -33,7 +33,7 @@ public class SurfaceAngleMask extends AbstractExtentMask { @Override public boolean test(Extent extent, BlockVector3 vector) { if (!vector.getBlock(getExtent()).isAir() && nextToAir(vector)) { - double angle = 1 - getAverageAirDirection(vector.toVector3(), size).getY(); + double angle = 1 - getAverageAirDirection(vector.toVector3(), size).y(); return (angle >= (min / 90.0) && angle <= (max / 90.0)); } return false; @@ -44,7 +44,7 @@ public class SurfaceAngleMask extends AbstractExtentMask { for (int i = -size; i <= size; i++) { for (int j = -size; j <= size; j++) { for (int k = -size; k <= size; k++) { - Vector3 block = Vector3.at(currentLocation.getX(), currentLocation.getY(), currentLocation.getZ()).add( + Vector3 block = Vector3.at(currentLocation.x(), currentLocation.y(), currentLocation.z()).add( 0.5, 0.5, 0.5 @@ -65,13 +65,13 @@ public class SurfaceAngleMask extends AbstractExtentMask { double y = 0.0; double z = 0.0; for (Vector3 vector3 : airDirections) { - x += vector3.getX(); - y += vector3.getY(); - z += vector3.getZ(); + x += vector3.x(); + y += vector3.y(); + z += vector3.z(); } Vector3 averageAirDirection = Vector3.at(x / airDirections.size(), y / airDirections.size(), z / airDirections.size()); - return (Double.isNaN(averageAirDirection.getY()) ? Vector3.ZERO : averageAirDirection.normalize()); + return (Double.isNaN(averageAirDirection.y()) ? Vector3.ZERO : averageAirDirection.normalize()); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/WallMakeMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/WallMakeMask.java index 4246f8a82..9d7b7a729 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/WallMakeMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/WallMakeMask.java @@ -14,8 +14,8 @@ public class WallMakeMask implements Mask { @Override public boolean test(BlockVector3 position) { - int x = position.getBlockX(); - int z = position.getBlockZ(); + int x = position.x(); + int z = position.z(); return !region.contains(x, z + 1) || !region.contains(x, z - 1) || !region.contains(x + 1, z) || !region.contains( x - 1, z diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/WallMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/WallMask.java index 40a323e51..eee5ab286 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/WallMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/WallMask.java @@ -23,9 +23,9 @@ public class WallMask extends AbstractMask { public boolean test(BlockVector3 bv) { vector.setComponents(bv); int count = 0; - double x = vector.getX(); - double y = vector.getY(); - double z = vector.getZ(); + double x = vector.x(); + double y = vector.y(); + double z = vector.z(); vector.mutX(x + 1); if (mask.test(vector) && ++count == min && max >= 8) { vector.mutX(x); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/XAxisMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/XAxisMask.java index 7531d1465..82c0eca02 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/XAxisMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/XAxisMask.java @@ -16,9 +16,9 @@ public class XAxisMask extends AbstractMask implements ResettableMask { @Override public boolean test(BlockVector3 vector) { if (layer == -1) { - layer = vector.getBlockX(); + layer = vector.x(); } - return vector.getBlockX() == layer; + return vector.x() == layer; } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/YAxisMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/YAxisMask.java index ee852e70e..15ee08192 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/YAxisMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/YAxisMask.java @@ -14,9 +14,9 @@ public class YAxisMask extends AbstractMask implements ResettableMask { @Override public boolean test(BlockVector3 vector) { if (layer == -1) { - layer = vector.getBlockY(); + layer = vector.y(); } - return vector.getBlockY() == layer; + return vector.y() == layer; } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ZAxisMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ZAxisMask.java index 269fc5dd8..648b712d2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ZAxisMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ZAxisMask.java @@ -14,9 +14,9 @@ public class ZAxisMask extends AbstractMask implements ResettableMask { @Override public boolean test(BlockVector3 vector) { if (layer == -1) { - layer = vector.getBlockZ(); + layer = vector.z(); } - return vector.getBlockZ() == layer; + return vector.z() == layer; } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AngleColorPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AngleColorPattern.java index a13061951..9f2becf76 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AngleColorPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AngleColorPattern.java @@ -42,9 +42,9 @@ public class AngleColorPattern extends AnglePattern { public > int getSlope(T block, BlockVector3 vector, Extent extent) { int slope = super.getSlope(block, vector, extent); if (slope != -1) { - int x = vector.getBlockX(); - int y = vector.getBlockY(); - int z = vector.getBlockZ(); + int x = vector.x(); + int y = vector.y(); + int z = vector.z(); int height = extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY); if (height > minY) { BlockState below = extent.getBlock(x, height - 1, z); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AnglePattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AnglePattern.java index 224d64434..caebfd6ff 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AnglePattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/AnglePattern.java @@ -31,9 +31,9 @@ public abstract class AnglePattern extends AbstractPattern { } public > int getSlope(T block, BlockVector3 vector, Extent extent) { - int x = vector.getBlockX(); - int y = vector.getBlockY(); - int z = vector.getBlockZ(); + int x = vector.x(); + int y = vector.y(); + int z = vector.z(); if (!block.getBlockType().getMaterial().isMovementBlocker()) { return -1; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern2D.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern2D.java index 99414ca25..483629af4 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern2D.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern2D.java @@ -33,7 +33,7 @@ public class BufferedPattern2D extends BufferedPattern { @Override public boolean set(BlockVector3 pos) { - return set.add(pos.getBlockX(), 0, pos.getBlockY()); + return set.add(pos.x(), 0, pos.y()); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExpressionPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExpressionPattern.java index 638872ea8..9276acb40 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExpressionPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExpressionPattern.java @@ -50,7 +50,7 @@ public class ExpressionPattern extends AbstractPattern { if (expression.getEnvironment() instanceof WorldEditExpressionEnvironment) { ((WorldEditExpressionEnvironment) expression.getEnvironment()).setCurrentBlock(vector.toVector3()); } - double combined = expression.evaluate(vector.getX(), vector.getY(), vector.getZ()); + double combined = expression.evaluate(vector.x(), vector.y(), vector.z()); return BlockState.getFromOrdinal((int) combined).toBaseBlock(); } catch (EvaluationException e) { e.printStackTrace(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java index 13df9ca6f..d30206534 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java @@ -37,7 +37,7 @@ public class Linear2DBlockPattern extends AbstractPattern { @Override public BaseBlock applyBlock(BlockVector3 position) { - int index = (position.getBlockX() / this.xScale + position.getBlockZ() / this.zScale) % patternsArray.length; + int index = (position.x() / this.xScale + position.z() / this.zScale) % patternsArray.length; if (index < 0) { index += patternsArray.length; } @@ -46,8 +46,8 @@ public class Linear2DBlockPattern extends AbstractPattern { @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - int index = (floorDiv(get.getBlockX(), this.xScale) - + floorDiv(get.getBlockZ(), this.zScale)) % patternsArray.length; + int index = (floorDiv(get.x(), this.xScale) + + floorDiv(get.z(), this.zScale)) % patternsArray.length; if (index < 0) { index += patternsArray.length; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java index 6c9d039d0..de6e3257b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java @@ -40,8 +40,8 @@ public class Linear3DBlockPattern extends AbstractPattern { @Override public BaseBlock applyBlock(BlockVector3 position) { - int index = (position.getBlockX() / this.xScale - + position.getBlockY() / this.yScale + position.getBlockZ() / this.zScale) % patternsArray.length; + int index = (position.x() / this.xScale + + position.y() / this.yScale + position.z() / this.zScale) % patternsArray.length; if (index < 0) { index += patternsArray.length; } @@ -50,8 +50,8 @@ public class Linear3DBlockPattern extends AbstractPattern { @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - int index = (floorDiv(get.getBlockX(), this.xScale) - + floorDiv(get.getBlockY(), this.yScale) + floorDiv(get.getBlockZ(), this.zScale)) % patternsArray.length; + int index = (floorDiv(get.x(), this.xScale) + + floorDiv(get.y(), this.yScale) + floorDiv(get.z(), this.zScale)) % patternsArray.length; if (index < 0) { index += patternsArray.length; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoXPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoXPattern.java index b4e9aac37..2d4da9528 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoXPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoXPattern.java @@ -24,15 +24,15 @@ public class NoXPattern extends AbstractPattern { @Override public BaseBlock applyBlock(BlockVector3 pos) { - mutable.mutY(pos.getY()); - mutable.mutZ(pos.getZ()); + mutable.mutY(pos.y()); + mutable.mutZ(pos.z()); return pattern.applyBlock(mutable); } @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - mutable.mutY(get.getY()); - mutable.mutZ(get.getZ()); + mutable.mutY(get.y()); + mutable.mutZ(get.z()); return pattern.apply(extent, mutable, set); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoYPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoYPattern.java index 2fefaedfc..12ef8174d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoYPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoYPattern.java @@ -24,15 +24,15 @@ public class NoYPattern extends AbstractPattern { @Override public BaseBlock applyBlock(BlockVector3 pos) { - mutable.mutX(pos.getX()); - mutable.mutZ(pos.getZ()); + mutable.mutX(pos.x()); + mutable.mutZ(pos.z()); return pattern.applyBlock(mutable); } @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - mutable.mutX(get.getX()); - mutable.mutZ(get.getZ()); + mutable.mutX(get.x()); + mutable.mutZ(get.z()); return pattern.apply(extent, mutable, set); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoZPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoZPattern.java index 8c100c5e3..f4d2a47ed 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoZPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoZPattern.java @@ -1,7 +1,6 @@ package com.fastasyncworldedit.core.function.pattern; import com.fastasyncworldedit.core.math.MutableBlockVector3; -import com.fastasyncworldedit.core.queue.Filter; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; @@ -25,15 +24,15 @@ public class NoZPattern extends AbstractPattern { @Override public BaseBlock applyBlock(BlockVector3 pos) { - mutable.mutX(pos.getX()); - mutable.mutY(pos.getY()); + mutable.mutX(pos.x()); + mutable.mutY(pos.y()); return pattern.applyBlock(mutable); } @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - mutable.mutX(get.getX()); - mutable.mutY(get.getY()); + mutable.mutX(get.x()); + mutable.mutY(get.y()); return pattern.apply(extent, mutable, set); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java index 9a5ca2ceb..5866766ef 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java @@ -40,10 +40,10 @@ public class OffsetPattern extends AbstractPattern { @Override public BaseBlock applyBlock(BlockVector3 position) { - mutable.mutX(position.getX() + dx); - mutable.mutY(position.getY() + dy); - mutable.mutZ(position.getZ() + dz); - if (mutable.getY() < minY || mutable.getY() > maxY) { + mutable.mutX(position.x() + dx); + mutable.mutY(position.y() + dy); + mutable.mutZ(position.z() + dz); + if (mutable.y() < minY || mutable.y() > maxY) { return BlockTypes.AIR.getDefaultState().toBaseBlock(); } return pattern.applyBlock(mutable); @@ -51,10 +51,10 @@ public class OffsetPattern extends AbstractPattern { @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - mutable.mutX(get.getX() + dx); - mutable.mutY(get.getY() + dy); - mutable.mutZ(get.getZ() + dz); - if (mutable.getY() < extent.getMinY() || mutable.getY() > extent.getMaxY()) { + mutable.mutX(get.x() + dx); + mutable.mutY(get.y() + dy); + mutable.mutZ(get.z() + dz); + if (mutable.y() < extent.getMinY() || mutable.y() > extent.getMaxY()) { return false; } return pattern.apply(extent, get, mutable); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java index c68bb24b1..5dc012f66 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java @@ -52,10 +52,10 @@ public class RandomOffsetPattern extends AbstractPattern { @Override public BaseBlock applyBlock(BlockVector3 position) { - mutable.mutX((position.getX() + r.nextInt(dx2) - dx)); - mutable.mutY((position.getY() + r.nextInt(dy2) - dy)); - mutable.mutZ((position.getZ() + r.nextInt(dz2) - dz)); - if (mutable.getY() < minY || mutable.getY() > maxY) { + mutable.mutX((position.x() + r.nextInt(dx2) - dx)); + mutable.mutY((position.y() + r.nextInt(dy2) - dy)); + mutable.mutZ((position.z() + r.nextInt(dz2) - dz)); + if (mutable.y() < minY || mutable.y() > maxY) { return BlockTypes.AIR.getDefaultState().toBaseBlock(); } return pattern.applyBlock(mutable); @@ -63,10 +63,10 @@ public class RandomOffsetPattern extends AbstractPattern { @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - mutable.mutX((set.getX() + r.nextInt(dx2) - dx)); - mutable.mutY((set.getY() + r.nextInt(dy2) - dy)); - mutable.mutZ((set.getZ() + r.nextInt(dz2) - dz)); - if (mutable.getY() < extent.getMinY() || mutable.getY() > extent.getMaxY()) { + mutable.mutX((set.x() + r.nextInt(dx2) - dx)); + mutable.mutY((set.y() + r.nextInt(dy2) - dy)); + mutable.mutZ((set.z() + r.nextInt(dz2) - dz)); + if (mutable.y() < extent.getMinY() || mutable.y() > extent.getMaxY()) { return false; } return pattern.apply(extent, get, mutable); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RelativePattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RelativePattern.java index 541aaa494..22e3a8d0b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RelativePattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RelativePattern.java @@ -35,10 +35,10 @@ public class RelativePattern extends AbstractPattern implements ResettablePatter if (origin == null) { origin = pos; } - mutable.mutX(pos.getX() - origin.getX()); - mutable.mutY(pos.getY() - origin.getY()); - mutable.mutZ(pos.getZ() - origin.getZ()); - if (mutable.getY() < minY || mutable.getY() > maxY) { + mutable.mutX(pos.x() - origin.x()); + mutable.mutY(pos.y() - origin.y()); + mutable.mutZ(pos.z() - origin.z()); + if (mutable.y() < minY || mutable.y() > maxY) { return BlockTypes.AIR.getDefaultState().toBaseBlock(); } return pattern.applyBlock(mutable); @@ -49,10 +49,10 @@ public class RelativePattern extends AbstractPattern implements ResettablePatter if (origin == null) { origin = set; } - mutable.mutX(set.getX() - origin.getX()); - mutable.mutY(set.getY() - origin.getY()); - mutable.mutZ(set.getZ() - origin.getZ()); - if (mutable.getY() < extent.getMinY() || mutable.getY() > extent.getMaxY()) { + mutable.mutX(set.x() - origin.x()); + mutable.mutY(set.y() - origin.y()); + mutable.mutZ(set.z() - origin.z()); + if (mutable.y() < extent.getMinY() || mutable.y() > extent.getMaxY()) { return false; } return pattern.apply(extent, get, mutable); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SolidRandomOffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SolidRandomOffsetPattern.java index 54ecf6676..698c0f199 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SolidRandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SolidRandomOffsetPattern.java @@ -63,13 +63,13 @@ public class SolidRandomOffsetPattern extends AbstractPattern { @Override public BaseBlock applyBlock(BlockVector3 position) { - mutable.mutX(position.getX() + r.nextInt(dx2) - dx); - mutable.mutY(position.getY() + r.nextInt(dy2) - dy); - mutable.mutZ(position.getZ() + r.nextInt(dz2) - dz); - if (mutable.getY() < minY || mutable.getY() > maxY) { + mutable.mutX(position.x() + r.nextInt(dx2) - dx); + mutable.mutY(position.y() + r.nextInt(dy2) - dy); + mutable.mutZ(position.z() + r.nextInt(dz2) - dz); + if (mutable.y() < minY || mutable.y() > maxY) { return BlockTypes.AIR.getDefaultState().toBaseBlock(); } - if (mutable.getY() < minY || mutable.getY() > maxY) { + if (mutable.y() < minY || mutable.y() > maxY) { return BlockTypes.AIR.getDefaultState().toBaseBlock(); } BaseBlock block = pattern.applyBlock(mutable); @@ -81,10 +81,10 @@ public class SolidRandomOffsetPattern extends AbstractPattern { @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - mutable.mutX(set.getX() + r.nextInt(dx2) - dx); - mutable.mutY(set.getY() + r.nextInt(dy2) - dy); - mutable.mutZ(set.getZ() + r.nextInt(dz2) - dz); - if (mutable.getY() < extent.getMinY() || mutable.getY() > extent.getMaxY()) { + mutable.mutX(set.x() + r.nextInt(dx2) - dx); + mutable.mutY(set.y() + r.nextInt(dy2) - dy); + mutable.mutZ(set.z() + r.nextInt(dz2) - dz); + if (mutable.y() < extent.getMinY() || mutable.y() > extent.getMaxY()) { return false; } BaseBlock block = pattern.applyBlock(mutable); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java index 03e3126be..a7a1a3e2e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java @@ -62,9 +62,9 @@ public class SurfaceRandomOffsetPattern extends AbstractPattern { next = buffer[i]; BlockVector3 dir = BreadthFirstSearch.DIAGONAL_DIRECTIONS[i]; next.setComponents( - cur.getBlockX() + dir.getBlockX(), - cur.getBlockY() + dir.getBlockY(), - cur.getBlockZ() + dir.getBlockZ() + cur.x() + dir.x(), + cur.y() + dir.y(), + cur.z() + dir.z() ); if (allowed(next)) { allowed[index++] = next; @@ -74,7 +74,7 @@ public class SurfaceRandomOffsetPattern extends AbstractPattern { return cur; } next = allowed[ThreadLocalRandom.current().nextInt(index)]; - cur.setComponents(next.getBlockX(), next.getBlockY(), next.getBlockZ()); + cur.setComponents(next.x(), next.y(), next.z()); } return cur; } @@ -85,9 +85,9 @@ public class SurfaceRandomOffsetPattern extends AbstractPattern { if (!block.getBlockType().getMaterial().isMovementBlocker()) { return false; } - int x = v.getBlockX(); - int y = v.getBlockY(); - int z = v.getBlockZ(); + int x = v.x(); + int y = v.y(); + int z = v.z(); v.mutY(y + 1); if (y < maxY && canPassthrough(v)) { v.mutY(y); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/visitor/AboveVisitor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/visitor/AboveVisitor.java index d2503447b..67a48e2f7 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/visitor/AboveVisitor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/visitor/AboveVisitor.java @@ -40,7 +40,7 @@ public class AboveVisitor extends RecursiveVisitor { @Override public boolean isVisitable(BlockVector3 from, BlockVector3 to) { - return (from.getBlockY() >= baseY) && super.isVisitable(from, to); + return (from.y() >= baseY) && super.isVisitable(from, to); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/visitor/DFSVisitor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/visitor/DFSVisitor.java index 58b6f0e41..6a84af071 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/visitor/DFSVisitor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/visitor/DFSVisitor.java @@ -64,13 +64,13 @@ public abstract class DFSVisitor implements Operation { IntTriple[] array = new IntTriple[directions.size()]; for (int i = 0; i < array.length; i++) { BlockVector3 dir = directions.get(i); - array[i] = new IntTriple(dir.getBlockX(), dir.getBlockY(), dir.getBlockZ()); + array[i] = new IntTriple(dir.x(), dir.y(), dir.z()); } return array; } public void visit(final BlockVector3 pos) { - Node node = new Node(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); + Node node = new Node(pos.x(), pos.y(), pos.z()); if (!this.hashQueue.contains(node)) { isVisitable(pos, pos); // Ignore this, just to initialize mask on this point queue.addFirst(new NodePair(null, node, 0)); @@ -102,7 +102,7 @@ public abstract class DFSVisitor implements Operation { mutable2.mutY(from.getY() + direction.y()); mutable2.mutZ(from.getZ() + direction.z()); if (isVisitable(mutable, mutable2)) { - Node adjacent = new Node(mutable2.getBlockX(), mutable2.getBlockY(), mutable2.getBlockZ()); + Node adjacent = new Node(mutable2.x(), mutable2.y(), mutable2.z()); if (!adjacent.equals(current.from)) { AtomicInteger adjacentCount = visited.get(adjacent); if (adjacentCount == null) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/visitor/DirectionalVisitor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/visitor/DirectionalVisitor.java index b7b14059b..f77b0b66b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/visitor/DirectionalVisitor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/visitor/DirectionalVisitor.java @@ -52,22 +52,22 @@ public class DirectionalVisitor extends RecursiveVisitor { @Override public boolean isVisitable(final BlockVector3 from, final BlockVector3 to) { - int dx = to.getBlockX() - from.getBlockX(); - int dz = to.getBlockZ() - from.getBlockZ(); - int dy = to.getBlockY() - from.getBlockY(); + int dx = to.x() - from.x(); + int dz = to.z() - from.z(); + int dy = to.y() - from.y(); if (dx != 0) { - if (dirVec.getBlockX() != 0 && dirVec.getBlockX() != dx) { + if (dirVec.x() != 0 && dirVec.x() != dx) { return false; } } if (dy != 0) { - if (dirVec.getBlockY() != 0 && dirVec.getBlockY() != dy) { + if (dirVec.y() != 0 && dirVec.y() != dy) { return false; } } if (dz != 0) { - if (dirVec.getBlockZ() != 0 && dirVec.getBlockZ() != dz) { + if (dirVec.z() != 0 && dirVec.z() != dz) { return false; } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/RollbackOptimizedHistory.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/RollbackOptimizedHistory.java index 1f01f99de..e11fda2b1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/RollbackOptimizedHistory.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/RollbackOptimizedHistory.java @@ -84,12 +84,12 @@ public class RollbackOptimizedHistory extends DiskStorageHistory { } public void setDimensions(BlockVector3 pos1, BlockVector3 pos2) { - this.minX = pos1.getBlockX(); - this.minY = pos1.getBlockY(); - this.minZ = pos1.getBlockZ(); - this.maxX = pos2.getBlockX(); - this.maxY = pos2.getBlockY(); - this.maxZ = pos2.getBlockZ(); + this.minX = pos1.x(); + this.minY = pos1.y(); + this.minZ = pos1.z(); + this.maxX = pos2.x(); + this.maxY = pos2.y(); + this.maxZ = pos2.z(); } public void setTime(long time) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java index 4bbe1a109..e5820fd44 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java @@ -127,18 +127,18 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { if (!tilesFrom.isEmpty()) { for (Map.Entry entry : tilesFrom.entrySet()) { BlockVector3 pos = entry.getKey(); - BlockState fromBlock = get.getBlock(pos.getX() & 15, pos.getY(), pos.getZ() & 15); - BlockState toBlock = set.getBlock(pos.getX() & 15, pos.getY(), pos.getZ() & 15); + BlockState fromBlock = get.getBlock(pos.x() & 15, pos.y(), pos.z() & 15); + BlockState toBlock = set.getBlock(pos.x() & 15, pos.y(), pos.z() & 15); if (fromBlock != toBlock || tilesTo.containsKey(pos)) { - addTileRemove(MainUtil.setPosition(entry.getValue(), entry.getKey().getX(), entry.getKey().getY(), - entry.getKey().getZ())); + addTileRemove(MainUtil.setPosition(entry.getValue(), entry.getKey().x(), entry.getKey().y(), + entry.getKey().z())); } } } if (!tilesTo.isEmpty()) { for (Map.Entry entry : tilesTo.entrySet()) { BlockVector3 pos = entry.getKey(); - addTileCreate(MainUtil.setPosition(entry.getValue(), pos.getX() + bx, pos.getY(), pos.getZ() + bz)); + addTileCreate(MainUtil.setPosition(entry.getValue(), pos.x() + bx, pos.y(), pos.z() + bz)); } } Set entRemoves = set.getEntityRemoves(); @@ -310,9 +310,9 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { } public void add(BlockVector3 loc, BaseBlock from, BaseBlock to) { - int x = loc.getBlockX(); - int y = loc.getBlockY(); - int z = loc.getBlockZ(); + int x = loc.x(); + int y = loc.y(); + int z = loc.z(); add(x, y, z, from, to); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/BlockBagChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/BlockBagChangeSet.java index 22833d3b5..c0dc9756c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/BlockBagChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/BlockBagChangeSet.java @@ -68,9 +68,9 @@ public class BlockBagChangeSet extends AbstractDelegateChangeSet { @Override public void add(BlockVector3 loc, BaseBlock from, BaseBlock to) { - int x = loc.getBlockX(); - int y = loc.getBlockY(); - int z = loc.getBlockZ(); + int x = loc.x(); + int y = loc.y(); + int z = loc.z(); add(x, y, z, from, to); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVector3ChunkMap.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVector3ChunkMap.java index a9f8a0210..919556847 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVector3ChunkMap.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVector3ChunkMap.java @@ -31,7 +31,7 @@ public class BlockVector3ChunkMap implements IAdaptedMap implements int cx = (int) MathMan.untripleWorldCoordX(triple); int cy = (int) MathMan.untripleWorldCoordY(triple); int cz = (int) MathMan.untripleWorldCoordZ(triple); - pos.mutX((cx << 11) + pos.getBlockX()); - pos.mutY((cy << 9) + pos.getBlockY()); - pos.mutZ((cz << 11) + pos.getBlockZ()); + pos.mutX((cx << 11) + pos.x()); + pos.mutY((cy << 9) + pos.y()); + pos.mutZ((cz << 11) + pos.z()); return pos.toImmutable(); } } @@ -124,7 +124,7 @@ public class BlockVectorSet extends AbstractCollection implements @Override public boolean contains(Object o) { if (o instanceof BlockVector3 v) { - return contains(v.getBlockX(), v.getBlockY(), v.getBlockZ()); + return contains(v.x(), v.y(), v.z()); } return false; } @@ -166,9 +166,9 @@ public class BlockVectorSet extends AbstractCollection implements int cy = (int) MathMan.untripleWorldCoordY(triple); int cz = (int) MathMan.untripleWorldCoordZ(triple); return mutable.setComponents( - (cx << 11) + localPos.getBlockX(), - (cy << 9) + localPos.getBlockY(), - (cz << 11) + localPos.getBlockZ() + (cx << 11) + localPos.x(), + (cy << 9) + localPos.y(), + (cz << 11) + localPos.z() ); } }; @@ -176,7 +176,7 @@ public class BlockVectorSet extends AbstractCollection implements @Override public boolean add(BlockVector3 vector) { - return add(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()); + return add(vector.x(), vector.y(), vector.z()); } public boolean add(int x, int y, int z) { @@ -209,7 +209,7 @@ public class BlockVectorSet extends AbstractCollection implements @Override public boolean remove(Object o) { if (o instanceof BlockVector3 v) { - return remove(v.getBlockX(), v.getBlockY(), v.getBlockZ()); + return remove(v.x(), v.y(), v.z()); } return false; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/LocalBlockVectorSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/LocalBlockVectorSet.java index 2ed3a2f63..72287b0a1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/LocalBlockVectorSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/LocalBlockVectorSet.java @@ -90,7 +90,7 @@ public class LocalBlockVectorSet implements BlockVector3Set { @Override public boolean contains(Object o) { if (o instanceof BlockVector3 v) { - return contains(v.getBlockX(), v.getBlockY(), v.getBlockZ()); + return contains(v.x(), v.y(), v.z()); } return false; } @@ -302,14 +302,14 @@ public class LocalBlockVectorSet implements BlockVector3Set { */ @Override public boolean add(BlockVector3 vector) { - return add(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()); + return add(vector.x(), vector.y(), vector.z()); } private int getIndex(BlockVector3 vector) { return MathMan.tripleSearchCoords( - vector.getBlockX() - offsetX, - vector.getBlockY() - offsetY, - vector.getBlockZ() - offsetZ + vector.x() - offsetX, + vector.y() - offsetY, + vector.z() - offsetZ ); } @@ -342,7 +342,7 @@ public class LocalBlockVectorSet implements BlockVector3Set { public boolean remove(Object o) { if (o instanceof BlockVector3) { BlockVector3 v = (BlockVector3) o; - return remove(v.getBlockX(), v.getBlockY(), v.getBlockZ()); + return remove(v.x(), v.y(), v.z()); } return false; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/heightmap/HeightMap.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/heightmap/HeightMap.java index f9b2ce914..eeafc8646 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/heightmap/HeightMap.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/heightmap/HeightMap.java @@ -10,7 +10,6 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; -import java.lang.reflect.InvocationTargetException; import java.util.concurrent.ThreadLocalRandom; public interface HeightMap { @@ -45,7 +44,7 @@ public interface HeightMap { boolean layers ) throws MaxChangedBlocksException { BlockVector3 top = session.getMaximumPoint(); - int maxY = top.getBlockY(); + int maxY = top.y(); Location min = new Location(session.getWorld(), pos.subtract(size, size, size).toVector3()); BlockVector3 max = pos.add(size, maxY, size); Region region = new CuboidRegion(session.getWorld(), min.toBlockPoint(), max); @@ -81,9 +80,9 @@ public interface HeightMap { int maxY = session.getMaxY(); int minY = session.getMinY(); int diameter = 2 * size + 1; - int centerX = pos.getBlockX(); - int centerZ = pos.getBlockZ(); - int centerY = pos.getBlockY(); + int centerX = pos.x(); + int centerZ = pos.z(); + int centerY = pos.y(); int[] oldData = new int[diameter * diameter]; int[] newData = new int[oldData.length]; if (layers) { // Pixel accuracy @@ -92,7 +91,7 @@ public interface HeightMap { } if (towards) { double sizePowInv = 1d / Math.pow(size, yscale); - int targetY = pos.getBlockY(); + int targetY = pos.y(); int tmpY = targetY; for (int x = -size; x <= size; x++) { int xx = centerX + x; @@ -133,7 +132,7 @@ public interface HeightMap { } } } else { - int height = pos.getBlockY(); + int height = pos.y(); for (int x = -size; x <= size; x++) { int xx = centerX + x; for (int z = -size; z <= size; z++) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/heightmap/RotatableHeightMap.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/heightmap/RotatableHeightMap.java index 291f8e754..a452a80f4 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/heightmap/RotatableHeightMap.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/heightmap/RotatableHeightMap.java @@ -24,7 +24,7 @@ public class RotatableHeightMap extends AbstractDelegateHeightMap { mutable.mutX(x); mutable.mutZ(z); BlockVector3 pos = transform.apply(mutable.setComponents(x, 0, z)).toBlockPoint(); - return super.getHeight(pos.getBlockX(), pos.getBlockZ()); + return super.getHeight(pos.x(), pos.z()); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/heightmap/ScalableHeightMap.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/heightmap/ScalableHeightMap.java index c4481da46..bc845127d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/heightmap/ScalableHeightMap.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/heightmap/ScalableHeightMap.java @@ -56,22 +56,22 @@ public class ScalableHeightMap implements HeightMap { public static ScalableHeightMap fromClipboard(Clipboard clipboard, int minY, int maxY) { BlockVector3 dim = clipboard.getDimensions(); - char[][] heightArray = new char[dim.getBlockX()][dim.getBlockZ()]; - int clipMinX = clipboard.getMinimumPoint().getBlockX(); - int clipMinZ = clipboard.getMinimumPoint().getBlockZ(); - int clipMinY = clipboard.getMinimumPoint().getBlockY(); - int clipMaxY = clipboard.getMaximumPoint().getBlockY(); + char[][] heightArray = new char[dim.x()][dim.z()]; + int clipMinX = clipboard.getMinimumPoint().x(); + int clipMinZ = clipboard.getMinimumPoint().z(); + int clipMinY = clipboard.getMinimumPoint().y(); + int clipMaxY = clipboard.getMaximumPoint().y(); int clipHeight = clipMaxY - clipMinY + 1; HashSet visited = new HashSet<>(); MutableBlockVector3 bv = new MutableBlockVector3(); for (BlockVector3 pos : clipboard.getRegion()) { - IntPair pair = new IntPair(pos.getBlockX(), pos.getBlockZ()); + IntPair pair = new IntPair(pos.x(), pos.z()); if (visited.contains(pair)) { continue; } visited.add(pair); - int xx = pos.getBlockX(); - int zz = pos.getBlockZ(); + int xx = pos.x(); + int zz = pos.z(); int highestY = clipMinY; bv.setComponents(pos); for (int y = clipMinY; y <= clipMaxY; y++) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/SimplexNoiseGenerator.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/SimplexNoiseGenerator.java index 8d8aeedf5..d690509dc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/SimplexNoiseGenerator.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/SimplexNoiseGenerator.java @@ -8,12 +8,12 @@ public class SimplexNoiseGenerator implements NoiseGenerator { @Override public float noise(Vector2 position) { - return convert(SimplexNoise.noise(position.getX(), position.getZ())); + return convert(SimplexNoise.noise(position.x(), position.z())); } @Override public float noise(Vector3 position) { - return convert(SimplexNoise.noise(position.getX(), position.getY(), position.getZ())); + return convert(SimplexNoise.noise(position.x(), position.y(), position.z())); } private float convert(double d) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java index ec6162798..a56fe27d5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java @@ -52,8 +52,8 @@ public interface IChunkExtent extends Extent { @Override default boolean setBiome(BlockVector3 position, BiomeType biome) { - final IChunk chunk = getOrCreateChunk(position.getX() >> 4, position.getZ() >> 4); - return chunk.setBiome(position.getX() & 15, position.getY(), position.getZ() & 15, biome); + final IChunk chunk = getOrCreateChunk(position.x() >> 4, position.z() >> 4); + return chunk.setBiome(position.x() & 15, position.y(), position.z() & 15, biome); } @Override @@ -76,8 +76,8 @@ public interface IChunkExtent extends Extent { @Override default BiomeType getBiome(BlockVector3 position) { - final IChunk chunk = getOrCreateChunk(position.getX() >> 4, position.getZ() >> 4); - return chunk.getBiomeType(position.getX() & 15, position.getY(), position.getZ() & 15); + final IChunk chunk = getOrCreateChunk(position.x() >> 4, position.z() >> 4); + return chunk.getBiomeType(position.x() & 15, position.y(), position.z() & 15); } @Override @@ -129,9 +129,9 @@ public interface IChunkExtent extends Extent { //Set pos List posList = new ArrayList<>(); - posList.add(new DoubleTag(location.getX())); - posList.add(new DoubleTag(location.getY())); - posList.add(new DoubleTag(location.getZ())); + posList.add(new DoubleTag(location.x())); + posList.add(new DoubleTag(location.y())); + posList.add(new DoubleTag(location.z())); map.put("Pos", new ListTag(DoubleTag.class, posList)); NBTUtils.addUUIDToMap(map, uuid); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java index 458b1858c..b2ac59cb2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java @@ -25,7 +25,7 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent, ITileInput { @Override default BiomeType getBiome(BlockVector3 position) { - return getBiomeType(position.getX(), position.getY(), position.getZ()); + return getBiomeType(position.x(), position.y(), position.z()); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java index 1af60b3a2..bc621e66a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java @@ -25,7 +25,7 @@ public interface IChunkSet extends IBlocks, OutputExtent { @Override default boolean setBiome(BlockVector3 position, BiomeType biome) { - return setBiome(position.getX(), position.getY(), position.getZ(), biome); + return setBiome(position.x(), position.y(), position.z(), biome); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java index 104167d30..c13373d9a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java @@ -152,7 +152,7 @@ public interface IQueueExtent extends Flushable, Trimable, ICh final Set chunks = region.getChunks(); ChunkFilterBlock block = null; for (BlockVector2 chunk : chunks) { - block = apply(block, filter, region, chunk.getX(), chunk.getZ(), full); + block = apply(block, filter, region, chunk.x(), chunk.z(), full); } flush(); return filter; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java index e88a9ccd3..38546ed1b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java @@ -135,7 +135,7 @@ public class ParallelQueueExtent extends PassthroughExtent { // if PQE is ever used with PARALLEL_THREADS = 1, or only one chunk is edited, just run sequentially while (chunksIter.hasNext()) { BlockVector2 pos = chunksIter.next(); - getExtent().apply(null, filter, region, pos.getX(), pos.getZ(), full); + getExtent().apply(null, filter, region, pos.x(), pos.z(), full); } } else { final ForkJoinTask[] tasks = IntStream.range(0, size).mapToObj(i -> handler.submit(() -> { @@ -159,8 +159,8 @@ public class ParallelQueueExtent extends PassthroughExtent { break; } final BlockVector2 pos = chunksIter.next(); - chunkX = pos.getX(); - chunkZ = pos.getZ(); + chunkX = pos.x(); + chunkZ = pos.z(); } block = queue.apply(block, newFilter, region, chunkX, chunkZ, full); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java index 6e06ce348..789547d83 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java @@ -356,7 +356,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen break; } loadCount++; - addChunkLoad(from.getBlockX(), from.getBlockZ()); + addChunkLoad(from.x(), from.z()); } } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharSetBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharSetBlocks.java index 9ab8734ea..da28e5925 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharSetBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharSetBlocks.java @@ -128,7 +128,7 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet { @Override public > boolean setBlock(BlockVector3 position, T block) throws WorldEditException { - return setBlock(position.getX(), position.getY(), position.getZ(), block); + return setBlock(position.x(), position.y(), position.z(), block); } @Override @@ -255,7 +255,7 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet { @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { - return setBiome(position.getX(), position.getY(), position.getZ(), biome); + return setBiome(position.x(), position.y(), position.z(), biome); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java index ca0dd3442..54331279f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java @@ -218,7 +218,7 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks { @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { - return setBiome(position.getX(), position.getY(), position.getZ(), biome); + return setBiome(position.x(), position.y(), position.z(), biome); } public void set(int x, int y, int z, char value) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/preloader/AsyncPreloader.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/preloader/AsyncPreloader.java index 7a74ed8ac..672ecfc93 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/preloader/AsyncPreloader.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/preloader/AsyncPreloader.java @@ -111,8 +111,8 @@ public class AsyncPreloader implements Preloader, Runnable { while (chunksIter.hasNext() && pair.getValue() == chunks) { // Ensure the queued load is still valid BlockVector2 chunk = chunksIter.next(); if (Settings.settings().REGION_RESTRICTIONS_OPTIONS.RESTRICT_TO_SAFE_RANGE) { - int x = chunk.getX(); - int z = chunk.getZ(); + int x = chunk.x(); + int z = chunk.z(); // if any chunk coord is outside 30 million blocks if (x > 1875000 || z > 1875000 || x < -1875000 || z < -1875000) { continue; @@ -130,7 +130,7 @@ public class AsyncPreloader implements Preloader, Runnable { } private void queueLoad(World world, BlockVector2 chunk) { - world.checkLoadedChunk(BlockVector3.at(chunk.getX() << 4, 0, chunk.getZ() << 4)); + world.checkLoadedChunk(BlockVector3.at(chunk.x() << 4, 0, chunk.z() << 4)); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/FuzzyRegion.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/FuzzyRegion.java index 58061bfa0..e080baeaf 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/FuzzyRegion.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/FuzzyRegion.java @@ -52,7 +52,7 @@ public class FuzzyRegion extends AbstractRegion { */ public void select(BlockVector3 position) { RecursiveVisitor search = new RecursiveVisitor(mask, p -> { - setMinMax(p.getBlockX(), p.getBlockY(), p.getBlockZ()); + setMinMax(p.x(), p.y(), p.z()); return true; }, 256, extent.getMinY(), extent.getMaxY(), extent); search.setVisited(set); @@ -120,7 +120,7 @@ public class FuzzyRegion extends AbstractRegion { @Override public boolean contains(BlockVector3 position) { - return contains(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + return contains(position.x(), position.y(), position.z()); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/PolyhedralRegion.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/PolyhedralRegion.java index 03dd750a5..dbfe840c8 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/PolyhedralRegion.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/PolyhedralRegion.java @@ -261,27 +261,27 @@ public class PolyhedralRegion extends AbstractRegion { if (!isDefined()) { return false; } - final int x = position.getBlockX(); - final int y = position.getBlockY(); - final int z = position.getBlockZ(); + final int x = position.x(); + final int y = position.y(); + final int z = position.z(); final BlockVector3 min = getMinimumPoint(); final BlockVector3 max = getMaximumPoint(); - if (x < min.getBlockX()) { + if (x < min.x()) { return false; } - if (x > max.getBlockX()) { + if (x > max.x()) { return false; } - if (z < min.getBlockZ()) { + if (z < min.z()) { return false; } - if (z > max.getBlockZ()) { + if (z > max.z()) { return false; } - if (y < min.getBlockY()) { + if (y < min.y()) { return false; } - if (y > max.getBlockY()) { + if (y > max.y()) { return false; } return containsRaw(position); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/RegionWrapper.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/RegionWrapper.java index e382583aa..40d0075e5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/RegionWrapper.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/RegionWrapper.java @@ -44,12 +44,12 @@ public class RegionWrapper extends CuboidRegion { public RegionWrapper(final BlockVector3 pos1, final BlockVector3 pos2) { super(pos1, pos2); - this.minX = Math.min(pos1.getBlockX(), pos2.getBlockX()); - this.minZ = Math.min(pos1.getBlockZ(), pos2.getBlockZ()); - this.maxX = Math.max(pos1.getBlockX(), pos2.getBlockX()); - this.maxZ = Math.max(pos1.getBlockZ(), pos2.getBlockZ()); - this.minY = Math.min(pos1.getBlockY(), pos2.getBlockY()); - this.maxY = Math.max(pos1.getBlockY(), pos2.getBlockY()); + this.minX = Math.min(pos1.x(), pos2.x()); + this.minZ = Math.min(pos1.z(), pos2.z()); + this.maxX = Math.max(pos1.x(), pos2.x()); + this.maxZ = Math.max(pos1.z(), pos2.z()); + this.minY = Math.min(pos1.y(), pos2.y()); + this.maxY = Math.max(pos1.y(), pos2.y()); } public static RegionWrapper GLOBAL() { @@ -61,12 +61,12 @@ public class RegionWrapper extends CuboidRegion { super.recalculate(); BlockVector3 pos1 = getMinimumPoint(); BlockVector3 pos2 = getMaximumPoint(); - this.minX = Math.min(pos1.getBlockX(), pos2.getBlockX()); - this.minZ = Math.min(pos1.getBlockZ(), pos2.getBlockZ()); - this.maxX = Math.max(pos1.getBlockX(), pos2.getBlockX()); - this.maxZ = Math.max(pos1.getBlockZ(), pos2.getBlockZ()); - this.minY = Math.min(pos1.getBlockY(), pos2.getBlockY()); - this.maxY = Math.max(pos1.getBlockY(), pos2.getBlockY()); + this.minX = Math.min(pos1.x(), pos2.x()); + this.minZ = Math.min(pos1.z(), pos2.z()); + this.maxX = Math.max(pos1.x(), pos2.x()); + this.maxZ = Math.max(pos1.z(), pos2.z()); + this.minY = Math.min(pos1.y(), pos2.y()); + this.maxY = Math.max(pos1.y(), pos2.y()); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/Triangle.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/Triangle.java index 46e934bee..2bb9fc5ac 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/Triangle.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/Triangle.java @@ -28,9 +28,9 @@ public class Triangle { private final double b; public Triangle(BlockVector3 pos1, BlockVector3 pos2, BlockVector3 pos3) { - verts[0] = new double[]{pos1.getBlockX(), pos1.getBlockY(), pos1.getBlockZ()}; - verts[1] = new double[]{pos2.getBlockX(), pos2.getBlockY(), pos2.getBlockZ()}; - verts[2] = new double[]{pos3.getBlockX(), pos3.getBlockY(), pos3.getBlockZ()}; + verts[0] = new double[]{pos1.x(), pos1.y(), pos1.z()}; + verts[1] = new double[]{pos2.x(), pos2.y(), pos2.z()}; + verts[2] = new double[]{pos3.x(), pos3.y(), pos3.z()}; radius[0] = RADIUS; radius[1] = RADIUS; radius[2] = RADIUS; @@ -72,9 +72,9 @@ public class Triangle { } public boolean contains(BlockVector3 pos) { - center[0] = pos.getBlockX() + RADIUS; - center[1] = pos.getBlockY() + RADIUS; - center[2] = pos.getBlockZ() + RADIUS; + center[0] = pos.x() + RADIUS; + center[1] = pos.y() + RADIUS; + center[2] = pos.z() + RADIUS; return overlaps(center, radius, verts); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/filter/CuboidRegionFilter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/filter/CuboidRegionFilter.java index d354eae3b..72413e115 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/filter/CuboidRegionFilter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/filter/CuboidRegionFilter.java @@ -19,10 +19,10 @@ public abstract class CuboidRegionFilter implements RegionFilter { public abstract void calculateRegions(); public void add(BlockVector2 pos1, BlockVector2 pos2) { - int ccx1 = pos1.getBlockX() >> 9; - int ccz1 = pos1.getBlockZ() >> 9; - int ccx2 = pos2.getBlockX() >> 9; - int ccz2 = pos2.getBlockZ() >> 9; + int ccx1 = pos1.x() >> 9; + int ccz1 = pos1.z() >> 9; + int ccx2 = pos2.x() >> 9; + int ccz2 = pos2.z() >> 9; for (int x = ccx1; x <= ccx2; x++) { for (int z = ccz1; z <= ccz2; z++) { if (!occupiedRegions.containsKey(x, z)) { @@ -39,10 +39,10 @@ public abstract class CuboidRegionFilter implements RegionFilter { } } } - int cx1 = pos1.getBlockX() >> 4; - int cz1 = pos1.getBlockZ() >> 4; - int cx2 = pos2.getBlockX() >> 4; - int cz2 = pos2.getBlockZ() >> 4; + int cx1 = pos1.x() >> 4; + int cz1 = pos1.z() >> 4; + int cx2 = pos2.x() >> 4; + int cz2 = pos2.z() >> 4; for (int chunkZ = cz1; chunkZ <= cz2; chunkZ++) { for (int chunkX = cx1; chunkX <= cx2; chunkX++) { unoccupiedChunks.remove(chunkX, chunkZ); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java index 1c5fe044a..117ab8fab 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java @@ -450,9 +450,9 @@ public class MainUtil { Location loc = entity.getLocation(); // Create a copy, because the list is immutable... List posList = new ArrayList<>(pos.getValue()); - posList.set(0, new DoubleTag(loc.getX())); - posList.set(1, new DoubleTag(loc.getY())); - posList.set(2, new DoubleTag(loc.getZ())); + posList.set(0, new DoubleTag(loc.x())); + posList.set(1, new DoubleTag(loc.y())); + posList.set(2, new DoubleTag(loc.z())); map.put("Pos", new ListTag(pos.getType(), posList)); } return new CompoundTag(map); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/WEManager.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/WEManager.java index b31853dd0..00ededf1a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/WEManager.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/WEManager.java @@ -183,8 +183,8 @@ public class WEManager { BlockVector3 rg2P1 = region2.getMinimumPoint(); BlockVector3 rg2P2 = region2.getMaximumPoint(); - return rg1P1.getBlockX() <= rg2P2.getBlockX() && rg1P2.getBlockX() >= rg2P1.getBlockX() - && rg1P1.getBlockZ() <= rg2P2.getBlockZ() && rg1P2.getBlockZ() >= rg2P1.getBlockZ(); + return rg1P1.x() <= rg2P2.x() && rg1P2.x() >= rg2P1.x() + && rg1P1.z() <= rg2P2.z() && rg1P2.z() >= rg2P1.z(); } public boolean regionContains(Region selection, HashSet mask) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockSet.java index 0706a39d2..06e7d7cff 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockSet.java @@ -35,7 +35,7 @@ public abstract class BlockSet extends AbstractRegion { @Override public boolean contains(BlockVector3 obj) { - return contains(obj.getX(), obj.getY(), obj.getZ()); + return contains(obj.x(), obj.y(), obj.z()); } protected final int lowestBit(long bitBuffer) { @@ -71,11 +71,11 @@ public abstract class BlockSet extends AbstractRegion { @Override public boolean add(BlockVector3 p) { - return add(p.getX(), p.getY(), p.getZ()); + return add(p.x(), p.y(), p.z()); } public boolean remove(BlockVector3 p) { - return remove(p.getX(), p.getY(), p.getZ()); + return remove(p.x(), p.y(), p.z()); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java index cadc35fc8..8bf9463f9 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java @@ -23,11 +23,11 @@ public interface BlockVector3Set extends Set { // Set default offset as many operations utilising a region are likely to start in a corner, this initialising the // LocalBlockVectorSet poorly // This needs to be ceiling as LocalBlockVector extends 1 block further "negative" - int offsetX = (int) Math.ceil((min.getX() + max.getX()) / 2d); - int offsetZ = (int) Math.ceil((min.getZ() + max.getZ()) / 2d); + int offsetX = (int) Math.ceil((min.x() + max.x()) / 2d); + int offsetZ = (int) Math.ceil((min.z() + max.z()) / 2d); int offsetY; if (region.getMinimumY() < -128 || region.getMaximumY() > 320) { - offsetY = (min.getY() + max.getY()) / 2; + offsetY = (min.y() + max.y()) / 2; } else { offsetY = 128; } @@ -43,7 +43,7 @@ public interface BlockVector3Set extends Set { * @return Appropriate {@link BlockVector3Set} implementation */ static BlockVector3Set getAppropriateVectorSet(BlockVector3 size) { - if (size.getBlockX() > 2048 || size.getBlockZ() > 2048 || size.getBlockY() > 512) { + if (size.x() > 2048 || size.z() > 2048 || size.y() > 512) { return new BlockVectorSet(); } else { return new LocalBlockVectorSet(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/MemBlockSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/MemBlockSet.java index 33fc963c3..68990cad1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/MemBlockSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/MemBlockSet.java @@ -1,7 +1,6 @@ package com.fastasyncworldedit.core.util.collection; import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.math.MutableBlockVector2; import com.fastasyncworldedit.core.math.MutableBlockVector3; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; @@ -167,9 +166,9 @@ public final class MemBlockSet extends BlockSet { @Override public boolean contains(Object o) { if (o instanceof BlockVector2 other) { - IRow rowx = rows[other.getX() - getChunkOffsetX()]; + IRow rowx = rows[other.x() - getChunkOffsetX()]; if (rowx instanceof RowX) { - return ((RowX) rowx).rows[other.getZ() - getChunkOffsetZ()] instanceof RowZ; + return ((RowX) rowx).rows[other.z() - getChunkOffsetZ()] instanceof RowZ; } } return false; @@ -269,11 +268,11 @@ public final class MemBlockSet extends BlockSet { @Override public boolean contains(Object o) { if (o instanceof BlockVector3 other) { - IRow rowx = rows[other.getX() - getChunkOffsetX()]; + IRow rowx = rows[other.x() - getChunkOffsetX()]; if (rowx instanceof RowX) { - IRow rowz = ((RowX) rowx).rows[other.getZ()]; + IRow rowz = ((RowX) rowx).rows[other.z()]; if (rowz instanceof RowZ) { - return ((RowZ) rowz).rows[other.getY() - (minSectionPosition << 4) - getChunkOffsetZ()] instanceof RowY; + return ((RowZ) rowz).rows[other.y() - (minSectionPosition << 4) - getChunkOffsetZ()] instanceof RowY; } } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/SimpleWorld.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/SimpleWorld.java index dcc65ae21..1619f114f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/SimpleWorld.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/SimpleWorld.java @@ -58,12 +58,12 @@ public interface SimpleWorld extends World { @Override default int getMaxY() { - return getMaximumPoint().getBlockY(); + return getMaximumPoint().y(); } @Override default int getMinY() { - return getMinimumPoint().getBlockY(); + return getMinimumPoint().y(); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/AsyncPlayer.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/AsyncPlayer.java index 700070611..077e87e8c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/AsyncPlayer.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/AsyncPlayer.java @@ -97,7 +97,7 @@ public class AsyncPlayer extends PlayerProxy { return false; } - while (y <= world.getMaximumPoint().getY()) { + while (y <= world.getMaximumPoint().y()) { // Found a ceiling! if (world.getBlock(mutable.mutY(y)).getBlockType().getMaterial() .isMovementBlocker()) { diff --git a/worldedit-core/src/main/java/com/sk89q/util/yaml/YAMLNode.java b/worldedit-core/src/main/java/com/sk89q/util/yaml/YAMLNode.java index d4cc816e7..a894cbe14 100644 --- a/worldedit-core/src/main/java/com/sk89q/util/yaml/YAMLNode.java +++ b/worldedit-core/src/main/java/com/sk89q/util/yaml/YAMLNode.java @@ -161,28 +161,28 @@ public class YAMLNode { if (value instanceof Vector3) { Map out = new LinkedHashMap<>(); Vector3 vec = (Vector3) value; - out.put("x", vec.getX()); - out.put("y", vec.getY()); - out.put("z", vec.getZ()); + out.put("x", vec.x()); + out.put("y", vec.y()); + out.put("z", vec.z()); return out; } else if (value instanceof BlockVector3) { Map out = new LinkedHashMap<>(); BlockVector3 vec = (BlockVector3) value; - out.put("x", vec.getBlockX()); - out.put("y", vec.getBlockY()); - out.put("z", vec.getBlockZ()); + out.put("x", vec.x()); + out.put("y", vec.y()); + out.put("z", vec.z()); return out; } else if (value instanceof Vector2) { Map out = new LinkedHashMap<>(); Vector2 vec = (Vector2) value; - out.put("x", vec.getX()); - out.put("z", vec.getZ()); + out.put("x", vec.x()); + out.put("z", vec.z()); return out; } else if (value instanceof BlockVector2) { Map out = new LinkedHashMap<>(); BlockVector2 vec = (BlockVector2) value; - out.put("x", vec.getBlockX()); - out.put("z", vec.getBlockZ()); + out.put("x", vec.x()); + out.put("z", vec.z()); return out; } 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 ecf859896..2e5e3c2ef 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -903,7 +903,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { //FAWE start - use extent - if (position.getY() < this.minY || position.getY() > this.maxY) { + if (position.y() < this.minY || position.y() > this.maxY) { return false; } this.changes++; @@ -984,7 +984,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { public > boolean setBlock(BlockVector3 position, B block, Stage stage) throws WorldEditException { //FAWE start - accumulate changes - if (position.getBlockY() < this.minY || position.getBlockY() > this.maxY) { + if (position.y() < this.minY || position.y() > this.maxY) { return false; } @@ -1014,7 +1014,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { */ @Deprecated public > boolean rawSetBlock(BlockVector3 position, B block) { - if (position.getBlockY() < this.minY || position.getBlockY() > this.maxY) { + if (position.y() < this.minY || position.y() > this.maxY) { return false; } @@ -1037,7 +1037,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { * @return whether the block changed */ public > boolean smartSetBlock(BlockVector3 position, B block) { - if (position.getBlockY() < this.minY || position.getBlockY() > this.maxY) { + if (position.y() < this.minY || position.y() > this.maxY) { return false; } @@ -1052,7 +1052,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { @Override @Deprecated public > boolean setBlock(BlockVector3 position, B block) throws MaxChangedBlocksException { - if (position.getBlockY() < this.minY || position.getBlockY() > this.maxY) { + if (position.y() < this.minY || position.y() > this.maxY) { return false; } @@ -1114,7 +1114,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public boolean setBlock(BlockVector3 position, Pattern pattern) throws MaxChangedBlocksException { - if (position.getBlockY() < this.minY || position.getBlockY() > this.maxY) { + if (position.y() < this.minY || position.y() > this.maxY) { return false; } @@ -1349,12 +1349,12 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { public > int fall(final Region region, boolean fullHeight, final B replace) { FlatRegion flat = asFlatRegion(region); - final int startPerformY = region.getMinimumPoint().getBlockY(); + final int startPerformY = region.getMinimumPoint().y(); final int startCheckY = fullHeight ? getMinY() : startPerformY; - final int endY = region.getMaximumPoint().getBlockY(); + final int endY = region.getMaximumPoint().y(); RegionVisitor visitor = new RegionVisitor(flat, pos -> { - int x = pos.getX(); - int z = pos.getZ(); + int x = pos.x(); + int z = pos.z(); int freeSpot = startCheckY; for (int y = startCheckY; y <= endY; y++) { if (y < startPerformY) { @@ -1479,8 +1479,8 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { // Avoid int overflow (negative coordinate space allows for overflow back round to positive if the depth is large enough). // Depth is always 1 or greater, thus the lower bound should always be <= origin y. - int lowerBound = origin.getBlockY() - depth + 1; - if (lowerBound > origin.getBlockY()) { + int lowerBound = origin.y() - depth + 1; + if (lowerBound > origin.y()) { lowerBound = Integer.MIN_VALUE; } @@ -1488,7 +1488,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { new RegionMask(new EllipsoidRegion(null, origin, Vector3.at(radius, radius, radius))), new BoundedHeightMask( Math.max(lowerBound, minY), - Math.min(maxY, origin.getBlockY()) + Math.min(maxY, origin.y()) ), Masks.negate(new ExistingBlockMask(this)) ); @@ -1502,7 +1502,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { if (recursive) { visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), minY, maxY, this); } else { - visitor = new DownwardVisitor(mask, replace, origin.getBlockY(), (int) (radius * 2 + 1), minY, maxY, this); + visitor = new DownwardVisitor(mask, replace, origin.y(), (int) (radius * 2 + 1), minY, maxY, this); } //FAWE end @@ -1600,11 +1600,11 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { Vector3 center = region.getCenter(); Region centerRegion = new CuboidRegion( getWorld(), // Causes clamping of Y range - BlockVector3.at(((int) center.getX()), ((int) center.getY()), ((int) center.getZ())), + BlockVector3.at(((int) center.x()), ((int) center.y()), ((int) center.z())), BlockVector3.at( - MathUtils.roundHalfUp(center.getX()), - MathUtils.roundHalfUp(center.getY()), - MathUtils.roundHalfUp(center.getZ()) + MathUtils.roundHalfUp(center.x()), + MathUtils.roundHalfUp(center.y()), + MathUtils.roundHalfUp(center.z()) ) ); return setBlocks(centerRegion, pattern); @@ -1754,8 +1754,8 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { BlockReplace replace = new BlockReplace(this, pattern); RegionOffset offset = new RegionOffset(BlockVector3.UNIT_Y, replace); //FAWE start - int minY = region.getMinimumPoint().getBlockY(); - int maxY = Math.min(getMaximumPoint().getBlockY(), region.getMaximumPoint().getBlockY() + 1); + int minY = region.getMinimumPoint().y(); + int maxY = Math.min(getMaximumPoint().y(), region.getMaximumPoint().y() + 1); SurfaceRegionFunction surface = new SurfaceRegionFunction(this, offset, minY, maxY); FlatRegionVisitor visitor = new FlatRegionVisitor(asFlatRegion(region), surface, this); //FAWE end @@ -1905,7 +1905,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { BlockVector3 disAbs = displace.abs(); - if (disAbs.getBlockX() < size.getBlockX() && disAbs.getBlockY() < size.getBlockY() && disAbs.getBlockZ() < size.getBlockZ()) { + if (disAbs.x() < size.x() && disAbs.y() < size.y() && disAbs.z() < size.z()) { // Buffer if overlapping enableQueue(); } @@ -2068,7 +2068,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { // There are boundaries that the routine needs to stay in Mask mask = new MaskIntersection( - new BoundedHeightMask(minY, Math.min(origin.getBlockY(), maxY)), + new BoundedHeightMask(minY, Math.min(origin.y(), maxY)), new RegionMask(new EllipsoidRegion(null, origin, Vector3.at(radius, radius, radius))), blockMask ); @@ -2156,15 +2156,15 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { } else if (height < 0) { height = -height; //FAWE start - mutableBlockVector3.mutY(mutableBlockVector3.getY() - height); + mutableBlockVector3.mutY(mutableBlockVector3.y() - height); //FAWE end } //FAWE start - if (mutableBlockVector3.getBlockY() < getWorld().getMinY()) { + if (mutableBlockVector3.y() < getWorld().getMinY()) { mutableBlockVector3.mutY(world.getMinY()); - } else if (mutableBlockVector3.getBlockY() + height - 1 > maxY) { - height = maxY - mutableBlockVector3.getBlockY() + 1; + } else if (mutableBlockVector3.y() + height - 1 > maxY) { + height = maxY - mutableBlockVector3.y() + 1; } //FAWE end @@ -2172,9 +2172,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { final double invRadiusZ = 1 / radiusZ; //FAWE start - int px = mutableBlockVector3.getBlockX(); - int py = mutableBlockVector3.getBlockY(); - int pz = mutableBlockVector3.getBlockZ(); + int px = mutableBlockVector3.x(); + int py = mutableBlockVector3.y(); + int pz = mutableBlockVector3.z(); final int ceilRadiusX = (int) Math.ceil(radiusX); final int ceilRadiusZ = (int) Math.ceil(radiusZ); @@ -2319,9 +2319,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { double ry2 = Math.pow(height, 2); double rz2 = Math.pow(radiusZ, 2); - int cx = pos.getX(); - int cy = pos.getY(); - int cz = pos.getZ(); + int cx = pos.x(); + int cy = pos.y(); + int cz = pos.z(); for (int y = 0; y < height; ++y) { double ySquaredMinusHeightOverHeightSquared = Math.pow(y - height, 2) / ry2; @@ -2403,18 +2403,18 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { radiusZ += 0.5; normal = normal.normalize(); - double nx = normal.getX(); - double ny = normal.getY(); - double nz = normal.getZ(); + double nx = normal.x(); + double ny = normal.y(); + double nz = normal.z(); final double invRadiusX = 1 / radiusX; final double invRadiusY = 1 / radiusY; final double invRadiusZ = 1 / radiusZ; - int px = pos.getBlockX(); - int py = pos.getBlockY(); - int pz = pos.getBlockZ(); + int px = pos.x(); + int py = pos.y(); + int pz = pos.z(); final int ceilRadiusX = (int) Math.ceil(radiusX); final int ceilRadiusY = (int) Math.ceil(radiusY); @@ -2545,9 +2545,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { final double invRadiusY = 1 / radiusY; final double invRadiusZ = 1 / radiusZ; - int px = pos.getBlockX(); - int py = pos.getBlockY(); - int pz = pos.getBlockZ(); + int px = pos.x(); + int py = pos.y(); + int pz = pos.z(); final int ceilRadiusX = (int) Math.ceil(radiusX); final int ceilRadiusY = (int) Math.ceil(radiusY); @@ -2654,9 +2654,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { */ public int makePyramid(BlockVector3 position, Pattern block, int size, boolean filled) throws MaxChangedBlocksException { //FAWE start - abbreviated logic - int bx = position.getX(); - int by = position.getY(); - int bz = position.getZ(); + int bx = position.x(); + int by = position.y(); + int bz = position.z(); int height = size; int yy, xx, x_x, zz, z_z; @@ -2715,9 +2715,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { int affected = 0; double radiusSq = radius * radius; - int ox = position.getBlockX(); - int oy = position.getBlockY(); - int oz = position.getBlockZ(); + int ox = position.x(); + int oy = position.y(); + int oz = position.z(); BlockState air = BlockTypes.AIR.getDefaultState(); BlockState water = BlockTypes.WATER.getDefaultState(); @@ -2804,7 +2804,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { public int simulateSnow(BlockVector3 position, double radius, int height) throws MaxChangedBlocksException { - return simulateSnow(new CylinderRegion(position, Vector2.at(radius, radius), position.getBlockY(), height), false); + return simulateSnow(new CylinderRegion(position, Vector2.at(radius, radius), position.y(), height), false); } /** @@ -2860,9 +2860,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { int affected = 0; final double radiusSq = radius * radius; - final int ox = position.getBlockX(); - final int oy = position.getBlockY(); - final int oz = position.getBlockZ(); + final int ox = position.x(); + final int oy = position.y(); + final int oz = position.z(); final BlockState grass = BlockTypes.GRASS_BLOCK.getDefaultState(); @@ -3077,7 +3077,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { } } if (expression.evaluate( - new double[]{scaled.getX(), scaled.getY(), scaled.getZ(), typeVar, dataVar}, + new double[]{scaled.x(), scaled.y(), scaled.z(), typeVar, dataVar}, timeout ) <= 0) { return null; @@ -3180,10 +3180,10 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { final Vector3 scaled = position.toVector3().subtract(zero).divide(unit); // transform - expression.evaluate(new double[]{scaled.getX(), scaled.getY(), scaled.getZ()}, timeout); - int xv = (int) Math.floor(x.getValue() * unit.getX() + zero2.getX()); - int yv = (int) Math.floor(y.getValue() * unit.getY() + zero2.getY()); - int zv = (int) Math.floor(z.getValue() * unit.getZ() + zero2.getZ()); + expression.evaluate(new double[]{scaled.x(), scaled.y(), scaled.z()}, timeout); + int xv = (int) Math.floor(x.getValue() * unit.x() + zero2.x()); + int yv = (int) Math.floor(y.getValue() * unit.y() + zero2.y()); + int zv = (int) Math.floor(z.getValue() * unit.z() + zero2.z()); BlockState get; if (yv >= minY && yv <= maxY) { @@ -3222,12 +3222,12 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { final BlockVector3 min = region.getMinimumPoint(); final BlockVector3 max = region.getMaximumPoint(); - final int minX = min.getBlockX(); - final int minY = min.getBlockY(); - final int minZ = min.getBlockZ(); - final int maxX = max.getBlockX(); - final int maxY = max.getBlockY(); - final int maxZ = max.getBlockZ(); + final int minX = min.x(); + final int minY = min.y(); + final int minZ = min.z(); + final int maxX = max.x(); + final int maxY = max.y(); + final int maxZ = max.z(); //FAWE start - mutable MutableBlockVector3 mutable = new MutableBlockVector3(); @@ -3316,12 +3316,12 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { public int drawLine(Pattern pattern, BlockVector3 pos1, BlockVector3 pos2, double radius, boolean filled, boolean flat) throws MaxChangedBlocksException { - int x1 = pos1.getBlockX(); - int y1 = pos1.getBlockY(); - int z1 = pos1.getBlockZ(); - int x2 = pos2.getBlockX(); - int y2 = pos2.getBlockY(); - int z2 = pos2.getBlockZ(); + int x1 = pos1.x(); + int y1 = pos1.y(); + int z1 = pos1.z(); + int x2 = pos2.x(); + int y2 = pos2.y(); + int z2 = pos2.z(); int tipx = x1; int tipy = y1; int tipz = z1; @@ -3416,12 +3416,12 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { BlockVector3 pos1 = vectors.get(i); BlockVector3 pos2 = vectors.get(i + 1); - int x1 = pos1.getBlockX(); - int y1 = pos1.getBlockY(); - int z1 = pos1.getBlockZ(); - int x2 = pos2.getBlockX(); - int y2 = pos2.getBlockY(); - int z2 = pos2.getBlockZ(); + int x1 = pos1.x(); + int y1 = pos1.y(); + int z1 = pos1.z(); + int x2 = pos2.x(); + int y2 = pos2.y(); + int z2 = pos2.z(); int tipx = x1; int tipy = y1; int tipz = z1; @@ -3532,9 +3532,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { int ceilrad = (int) Math.ceil(radius); for (BlockVector3 v : vset) { - int tipx = v.getBlockX(); - int tipy = v.getBlockY(); - int tipz = v.getBlockZ(); + int tipx = v.x(); + int tipy = v.y(); + int tipz = v.z(); for (int loopx = tipx - ceilrad; loopx <= tipx + ceilrad; loopx++) { for (int loopy = tipy - ceilrad; loopy <= tipy + ceilrad; loopy++) { @@ -3557,13 +3557,13 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { final LocalBlockVectorSet returnset = new LocalBlockVectorSet(); final int ceilrad = (int) Math.ceil(radius); for (BlockVector3 v : vset) { - final int tipx = v.getBlockX(); - final int tipy = v.getBlockY(); - final int tipz = v.getBlockZ(); + final int tipx = v.x(); + final int tipy = v.y(); + final int tipz = v.z(); for (int loopx = tipx - ceilrad; loopx <= tipx + ceilrad; loopx++) { for (int loopz = tipz - ceilrad; loopz <= tipz + ceilrad; loopz++) { if (MathMan.hypot(loopx - tipx, 0, loopz - tipz) <= radius) { - returnset.add(loopx, v.getBlockY(), loopz); + returnset.add(loopx, v.y(), loopz); } } } @@ -3576,9 +3576,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { final LocalBlockVectorSet newset = new LocalBlockVectorSet(); newset.addAll(vset); for (BlockVector3 v : newset) { - final int x = v.getX(); - final int y = v.getY(); - final int z = v.getZ(); + final int x = v.x(); + final int y = v.y(); + final int z = v.z(); if (!(newset.contains(x + 1, y, z) && newset.contains(x - 1, y, z) && newset.contains(x, y, z + 1) @@ -3595,9 +3595,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { final LocalBlockVectorSet newset = new LocalBlockVectorSet(); newset.addAll(vset); for (BlockVector3 v : newset) { - final int x = v.getX(); - final int y = v.getY(); - final int z = v.getZ(); + final int x = v.x(); + final int y = v.y(); + final int z = v.z(); if (!(newset.contains(x + 1, y, z) && newset.contains(x - 1, y, z) && newset.contains(x, y + 1, z) @@ -3668,9 +3668,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { @Override protected BiomeType getBiome(int x, int y, int z, BiomeType defaultBiomeType) { environment.setCurrentBlock(x, y, z); - double scaledX = (x - zero.getX()) / unit.getX(); - double scaledY = (y - zero.getY()) / unit.getY(); - double scaledZ = (z - zero.getZ()) / unit.getZ(); + double scaledX = (x - zero.x()) / unit.x(); + double scaledY = (y - zero.y()) / unit.y(); + double scaledZ = (z - zero.z()) / unit.z(); try { if (expression.evaluate(new double[]{scaledX, scaledY, scaledZ}, timeout) <= 0) { @@ -3717,9 +3717,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { } private void setExistingBlocks(BlockVector3 pos1, BlockVector3 pos2) { - for (int x = pos1.getX(); x <= pos2.getX(); x++) { - for (int z = pos1.getBlockZ(); z <= pos2.getBlockZ(); z++) { - for (int y = pos1.getY(); y <= pos2.getY(); y++) { + for (int x = pos1.x(); x <= pos2.x(); x++) { + for (int z = pos1.z(); z <= pos2.z(); z++) { + for (int y = pos1.y(); y <= pos2.y(); y++) { setBlock(x, y, z, getFullBlock(x, y, z)); } } @@ -3735,10 +3735,10 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { if (fe != null && cuboid) { BlockVector3 max = region.getMaximumPoint(); BlockVector3 min = region.getMinimumPoint(); - if (!fe.contains(max.getBlockX(), max.getBlockY(), max.getBlockZ()) && !fe.contains( - min.getBlockX(), - min.getBlockY(), - min.getBlockZ() + if (!fe.contains(max.x(), max.y(), max.z()) && !fe.contains( + min.x(), + min.y(), + min.z() )) { throw FaweCache.OUTSIDE_REGION; } @@ -3748,17 +3748,17 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { MutableBlockVector3 mutable2 = new MutableBlockVector3(); MutableBlockVector2 mutable2D = new MutableBlockVector2(); for (BlockVector2 chunk : chunks) { - final int cx = chunk.getBlockX(); - final int cz = chunk.getBlockZ(); + final int cx = chunk.x(); + final int cz = chunk.z(); final int bx = cx << 4; final int bz = cz << 4; final BlockVector3 cmin = BlockVector3.at(bx, 0, bz); final BlockVector3 cmax = cmin.add(15, maxY, 15); final boolean containsBot1 = - fe == null || fe.contains(cmin.getBlockX(), cmin.getBlockY(), cmin.getBlockZ()); + fe == null || fe.contains(cmin.x(), cmin.y(), cmin.z()); final boolean containsBot2 = region.contains(cmin); final boolean containsTop1 = - fe == null || fe.contains(cmax.getBlockX(), cmax.getBlockY(), cmax.getBlockZ()); + fe == null || fe.contains(cmax.x(), cmax.y(), cmax.z()); final boolean containsTop2 = region.contains(cmax); if (containsBot2 && containsTop2 && !containsBot1 && !containsTop1) { continue; @@ -3917,15 +3917,15 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { double seedY = ThreadLocalRandom.current().nextDouble(); double seedZ = ThreadLocalRandom.current().nextDouble(); - int px = position.getBlockX(); - int py = position.getBlockY(); - int pz = position.getBlockZ(); + int px = position.x(); + int py = position.y(); + int pz = position.z(); double distort = frequency / size; - double modX = 1d / radius.getX(); - double modY = 1d / radius.getY(); - double modZ = 1d / radius.getZ(); + double modX = 1d / radius.x(); + double modY = 1d / radius.y(); + double modZ = 1d / radius.z(); int r = (int) size; int radiusSqr = (int) (size * size); int sizeInt = (int) size * 2; @@ -3986,9 +3986,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { // so it must be set each time mutable.setComponents(xr, yr, zr); Vector3 pt = transform.apply(mutable); - x = MathMan.roundInt(pt.getX()); - y = MathMan.roundInt(pt.getY()); - z = MathMan.roundInt(pt.getZ()); + x = MathMan.roundInt(pt.x()); + y = MathMan.roundInt(pt.y()); + z = MathMan.roundInt(pt.z()); xScaled = Math.abs(x) * modX; yScaled = Math.abs(y) * modY; 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 bdd6a4ed4..7160be750 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 @@ -462,7 +462,7 @@ public class BrushCommands { @Arg(desc = "double", def = "50") double amplitude ) throws WorldEditException { - double max = MathMan.max(radius.getX(), radius.getY(), radius.getZ()); + double max = MathMan.max(radius.x(), radius.y(), radius.z()); worldEdit.checkMaxBrushRadius( max, context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) @@ -1368,15 +1368,15 @@ public class BrushCommands { BlockVector3 size = clipboard.getDimensions(); worldEdit.checkMaxBrushRadius( - size.getBlockX() / 2D - 1, + size.x() / 2D - 1, context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) ); worldEdit.checkMaxBrushRadius( - size.getBlockY() / 2D - 1, + size.y() / 2D - 1, context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) ); worldEdit.checkMaxBrushRadius( - size.getBlockZ() / 2D - 1, + size.z() / 2D - 1, context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) ); 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 177366651..b4037ba15 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 @@ -150,8 +150,8 @@ public class ClipboardCommands { BlockVector3 max = region.getMaximumPoint(); long volume = - ((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min - .getZ() + 1); + ((long) max.x() - (long) min.x() + 1) * ((long) max.y() - (long) min.y() + 1) * ((long) max.z() - (long) min + .z() + 1); FaweLimit limit = actor.getLimit(); if (volume >= limit.MAX_CHECKS) { throw FaweCache.MAX_CHECKS; @@ -184,8 +184,8 @@ public class ClipboardCommands { ) throws WorldEditException { BlockVector3 min = region.getMinimumPoint(); BlockVector3 max = region.getMaximumPoint(); - long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min - .getZ() + 1)); + long volume = (((long) max.x() - (long) min.x() + 1) * ((long) max.y() - (long) min.y() + 1) * ((long) max.z() - (long) min + .z() + 1)); FaweLimit limit = actor.getLimit(); if (volume >= limit.MAX_CHECKS) { throw FaweCache.MAX_CHECKS; @@ -257,8 +257,8 @@ public class ClipboardCommands { BlockVector3 min = region.getMinimumPoint(); BlockVector3 max = region.getMaximumPoint(); - long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min - .getZ() + 1)); + long volume = (((long) max.x() - (long) min.x() + 1) * ((long) max.y() - (long) min.y() + 1) * ((long) max.z() - (long) min + .z() + 1)); FaweLimit limit = actor.getLimit(); if (volume >= limit.MAX_CHECKS) { throw FaweCache.MAX_CHECKS; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java index 14e3d3307..d32504ad4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java @@ -79,12 +79,12 @@ public class FlattenedClipboardTransform { Vector3[] corners = new Vector3[]{ minimum, maximum, - minimum.withX(maximum.getX()), - minimum.withY(maximum.getY()), - minimum.withZ(maximum.getZ()), - maximum.withX(minimum.getX()), - maximum.withY(minimum.getY()), - maximum.withZ(minimum.getZ()) + minimum.withX(maximum.x()), + minimum.withY(maximum.y()), + minimum.withZ(maximum.z()), + maximum.withX(minimum.x()), + maximum.withY(minimum.y()), + maximum.withZ(minimum.z()) }; for (int i = 0; i < corners.length; i++) { 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 90b59cb52..4b2f98e0c 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 @@ -440,13 +440,13 @@ public class GenerationCommands { zero = max.add(min).multiply(0.5); unit = max.subtract(zero); - if (unit.getX() == 0) { + if (unit.x() == 0) { unit = unit.withX(1.0); } - if (unit.getY() == 0) { + if (unit.y() == 0) { unit = unit.withY(1.0); } - if (unit.getZ() == 0) { + if (unit.z() == 0) { unit = unit.withZ(1.0); } } @@ -526,13 +526,13 @@ public class GenerationCommands { zero = max.add(min).multiply(0.5); unit = max.subtract(zero); - if (unit.getX() == 0) { + if (unit.x() == 0) { unit = unit.withX(1.0); } - if (unit.getY() == 0) { + if (unit.y() == 0) { unit = unit.withY(1.0); } - if (unit.getZ() == 0) { + if (unit.z() == 0) { unit = unit.withZ(1.0); } } @@ -636,7 +636,7 @@ public class GenerationCommands { MainUtil.checkImageHost(url.toURI()); if (dimensions != null) { checkCommandArgument( - (long) dimensions.getX() * dimensions.getZ() <= Settings.settings().WEB.MAX_IMAGE_SIZE, + (long) dimensions.x() * dimensions.z() <= Settings.settings().WEB.MAX_IMAGE_SIZE, Caption.of("fawe.error.image-dimensions", Settings.settings().WEB.MAX_IMAGE_SIZE) ); } @@ -644,7 +644,7 @@ public class GenerationCommands { Future future = executor.submit(() -> { BufferedImage image = MainUtil.readImage(url); if (dimensions != null) { - image = ImageUtil.getScaledInstance(image, dimensions.getBlockX(), dimensions.getBlockZ(), + image = ImageUtil.getScaledInstance(image, dimensions.x(), dimensions.z(), RenderingHints.VALUE_INTERPOLATION_BILINEAR, false ); } @@ -668,8 +668,8 @@ public class GenerationCommands { CuboidRegion region = new CuboidRegion(pos1, pos2); final BufferedImage finalImage = image; RegionVisitor visitor = new RegionVisitor(region, pos -> { - int x = pos.getBlockX() - pos1.getBlockX(); - int z = pos.getBlockZ() - pos1.getBlockZ(); + int x = pos.x() - pos1.x(); + int z = pos.z() - pos1.z(); int color = finalImage.getRGB(x, z); BlockType block = tu.getNearestBlock(color); if (block != null) { @@ -735,7 +735,7 @@ public class GenerationCommands { @Arg(desc = "double", def = "50") double amplitude ) throws WorldEditException { - double max = MathMan.max(radius.getX(), radius.getY(), radius.getZ()); + double max = MathMan.max(radius.x(), radius.y(), radius.z()); worldEdit.checkMaxRadius(max, actor); BlockVector3 pos = session.getPlacementPosition(actor); int affected = editSession.makeBlob( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java index 08f48b265..8d28ad1eb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java @@ -13,10 +13,7 @@ import com.fastasyncworldedit.core.util.MainUtil; import com.fastasyncworldedit.core.util.StringMan; import com.google.common.base.Function; import com.google.common.collect.Lists; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.EditSessionBuilder; import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.command.util.CommandPermissions; @@ -25,7 +22,6 @@ import com.sk89q.worldedit.command.util.annotation.Confirm; import com.sk89q.worldedit.command.util.annotation.Time; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.function.operation.ChangeSetExecutor; import com.sk89q.worldedit.history.changeset.ChangeSet; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; @@ -245,11 +241,11 @@ public class HistorySubCommands { BlockVector3 pos1 = edit.getMinimumPoint(); BlockVector3 pos2 = edit.getMaximumPoint(); - double distanceX = Math.min(Math.abs(pos1.getX() - origin.getX()), Math.abs(pos2.getX() - origin.getX())); - double distanceZ = Math.min(Math.abs(pos1.getZ() - origin.getZ()), Math.abs(pos2.getZ() - origin.getZ())); + double distanceX = Math.min(Math.abs(pos1.x() - origin.x()), Math.abs(pos2.x() - origin.x())); + double distanceZ = Math.min(Math.abs(pos1.z() - origin.z()), Math.abs(pos2.z() - origin.z())); int distance = (int) Math.sqrt(distanceX * distanceX + distanceZ * distanceZ); - BlockVector2 dirVec = BlockVector2.at(edit.getOriginX() - origin.getX(), edit.getOriginZ() - origin.getZ()); + BlockVector2 dirVec = BlockVector2.at(edit.getOriginX() - origin.x(), edit.getOriginZ() - origin.z()); Direction direction = Direction.findClosest(dirVec.toVector3(), Direction.Flag.ALL); long seconds = (System.currentTimeMillis() - edit.getBDFile().lastModified()) / 1000; @@ -326,13 +322,13 @@ public class HistorySubCommands { BlockVector3 pos1 = rollback.getMinimumPoint(); BlockVector3 pos2 = rollback.getMaximumPoint(); - double distanceX = Math.min(Math.abs(pos1.getX() - origin.getX()), Math.abs(pos2.getX() - origin.getX())); - double distanceZ = Math.min(Math.abs(pos1.getZ() - origin.getZ()), Math.abs(pos2.getZ() - origin.getZ())); + double distanceX = Math.min(Math.abs(pos1.x() - origin.x()), Math.abs(pos2.x() - origin.x())); + double distanceZ = Math.min(Math.abs(pos1.z() - origin.z()), Math.abs(pos2.z() - origin.z())); int distance = (int) Math.sqrt(distanceX * distanceX + distanceZ * distanceZ); BlockVector2 dirVec = BlockVector2.at( - rollback.getOriginX() - origin.getX(), - rollback.getOriginZ() - origin.getZ() + rollback.getOriginX() - origin.x(), + rollback.getOriginZ() - origin.z() ); Direction direction = Direction.findClosest(dirVec.toVector3(), Direction.Flag.ALL); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index 73cb34274..6a121aa02 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 @@ -351,8 +351,8 @@ public class RegionCommands { int affected = 0; while (iter.hasNext()) { BlockVector2 pos = iter.next(); - int x = pos.getBlockX(); - int z = pos.getBlockZ(); + int x = pos.x(); + int z = pos.z(); //FAWE start - world min/maxY y = editSession.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY); //FAWE end @@ -449,8 +449,8 @@ public class RegionCommands { //FAWE end BlockVector3 min = region.getMinimumPoint(); BlockVector3 max = region.getMaximumPoint(); - long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min - .getZ() + 1)); + long volume = (((long) max.x() - (long) min.x() + 1) * ((long) max.y() - (long) min.y() + 1) * ((long) max.z() - (long) min + .z() + 1)); FaweLimit limit = actor.getLimit(); if (volume >= limit.MAX_CHECKS) { throw FaweCache.MAX_CHECKS; @@ -772,13 +772,13 @@ public class RegionCommands { zero = max.add(min).divide(2); unit = max.subtract(zero); - if (unit.getX() == 0) { + if (unit.x() == 0) { unit = unit.withX(1.0); } - if (unit.getY() == 0) { + if (unit.y() == 0) { unit = unit.withY(1.0); } - if (unit.getZ() == 0) { + if (unit.z() == 0) { unit = unit.withZ(1.0); } } 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 a643742d2..d8e0943dc 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 @@ -262,12 +262,12 @@ public class SelectionCommands { actor.print(Caption.of( "worldedit.chunk.selected-multiple", - TextComponent.of(minChunk.getBlockX()), - TextComponent.of(minChunk.getBlockY()), - TextComponent.of(minChunk.getBlockZ()), - TextComponent.of(maxChunk.getBlockX()), - TextComponent.of(maxChunk.getBlockY()), - TextComponent.of(maxChunk.getBlockZ()) + TextComponent.of(minChunk.x()), + TextComponent.of(minChunk.y()), + TextComponent.of(minChunk.z()), + TextComponent.of(maxChunk.x()), + TextComponent.of(maxChunk.y()), + TextComponent.of(maxChunk.z()) )); } else { BlockVector3 minChunk; @@ -290,9 +290,9 @@ public class SelectionCommands { actor.print(Caption.of( "worldedit.chunk.selected", - TextComponent.of(minChunk.getBlockX()), - TextComponent.of(minChunk.getBlockY()), - TextComponent.of(minChunk.getBlockZ()) + TextComponent.of(minChunk.x()), + TextComponent.of(minChunk.y()), + TextComponent.of(minChunk.z()) )); } @@ -538,10 +538,10 @@ public class SelectionCommands { .subtract(region.getMinimumPoint()).add(1, 1, 1); BlockVector3 origin = clipboard.getOrigin(); - String sizeStr = size.getBlockX() + "*" + size.getBlockY() + "*" + size.getBlockZ(); - String originStr = origin.getBlockX() + "," + origin.getBlockY() + "," + origin.getBlockZ(); + String sizeStr = size.x() + "*" + size.y() + "*" + size.z(); + String originStr = origin.x() + "," + origin.y() + "," + origin.z(); - long numBlocks = ((long) size.getBlockX() * size.getBlockY() * size.getBlockZ()); + long numBlocks = ((long) size.x() * size.y() * size.z()); actor.print(Caption.of( "worldedit.size.offset", TextComponent.of(name), 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 a336f4b12..a289f7cff 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 @@ -50,19 +50,12 @@ 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.block.BlockReplace; import com.sk89q.worldedit.function.mask.BlockTypeMask; -import com.sk89q.worldedit.function.mask.BoundedHeightMask; import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.function.mask.MaskIntersection; -import com.sk89q.worldedit.function.mask.Masks; -import com.sk89q.worldedit.function.mask.RegionMask; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.function.visitor.DownwardVisitor; import com.sk89q.worldedit.function.visitor.EntityVisitor; -import com.sk89q.worldedit.function.visitor.RecursiveVisitor; import com.sk89q.worldedit.internal.annotation.Direction; import com.sk89q.worldedit.internal.annotation.VertHeight; import com.sk89q.worldedit.internal.expression.EvaluationException; @@ -70,10 +63,8 @@ import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector2; -import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CylinderRegion; -import com.sk89q.worldedit.regions.EllipsoidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.formatting.component.SubtleFormat; import com.sk89q.worldedit.util.formatting.text.Component; @@ -550,8 +541,8 @@ public class UtilityCommands { CylinderRegion region = new CylinderRegion( position, Vector2.at(size, size), - position.getBlockY() - height, - position.getBlockY() + height + position.y() - height, + position.y() + height ); int affected = editSession.simulateSnow(region, stack); actor.print(Caption.of( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/OffsetConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/OffsetConverter.java index 88b74a05f..22c755cb5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/OffsetConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/OffsetConverter.java @@ -98,9 +98,9 @@ public class OffsetConverter implements ArgumentConverter { // Create an affine transform of the columns (col4 is empty due to no translation) AffineTransform transform = new AffineTransform( - m1.getX(), m2.getX(), m3.getX(), 0, - m1.getY(), m2.getY(), m3.getY(), 0, - m1.getZ(), m2.getZ(), m3.getZ(), 0 + m1.x(), m2.x(), m3.x(), 0, + m1.y(), m2.y(), m3.y(), 0, + m1.z(), m2.z(), m3.z(), 0 ); return transform 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 c4d45d683..6021102a2 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 @@ -380,7 +380,7 @@ public class BrushTool pitch = 23 - (pitch / 4); d += (int) (Math.sin(Math.toRadians(pitch)) * 50); final Vector3 vector = loc.getDirection().withY(0).normalize().multiply(d) - .add(loc.getX(), loc.getY(), loc.getZ()); + .add(loc.x(), loc.y(), loc.z()); return offset(vector, loc).toBlockPoint(); } case TARGET_POINT_HEIGHT: { 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 b82601288..bfa19b7e3 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 @@ -38,11 +38,11 @@ public class GravityBrush implements Brush { public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { //FAWE start - Ours operates differently to upstream, but does the same - double endY = position.getY() + size; - double startPerformY = Math.max(editSession.getMinY(), position.getY() - size); + double endY = position.y() + size; + double startPerformY = Math.max(editSession.getMinY(), position.y() - size); double startCheckY = fullHeight ? editSession.getMinY() : startPerformY; - for (double x = position.getX() + size; x > position.getX() - size; --x) { - for (double z = position.getZ() + size; z > position.getZ() - size; --z) { + for (double x = position.x() + size; x > position.x() - size; --x) { + for (double z = position.z() + size; z > position.z() - size; --z) { double freeSpot = startCheckY; for (double y = startCheckY; y <= endY; y++) { BlockState block = editSession.getBlock((int) x, (int) y, (int) z); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/Confirm.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/Confirm.java index 37ea4abeb..b8980afc8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/Confirm.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/Confirm.java @@ -3,7 +3,6 @@ package com.sk89q.worldedit.command.util.annotation; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.util.task.InterruptableCondition; import com.sk89q.worldedit.IncompleteRegionException; -import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.event.Event; import com.sk89q.worldedit.event.platform.CommandEvent; @@ -57,7 +56,7 @@ public @interface Confirm { .orElseThrow(IncompleteRegionException::new); BlockVector3 pos1 = region.getMinimumPoint(); BlockVector3 pos2 = region.getMaximumPoint(); - long area = (pos2.getX() - pos1.getX()) * (pos2.getZ() - pos1.getZ() + 1) + long area = (pos2.x() - pos1.x()) * (pos2.z() - pos1.z() + 1) * (long) value; long max = 2 << 18; if (max != -1 && area > max) { 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 ae4eb2144..5337fe720 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 @@ -162,8 +162,8 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { public void findFreePosition(Location searchPos) { Extent world = searchPos.getExtent(); - int worldMinY = world.getMinimumPoint().getY(); - int worldMaxY = world.getMaximumPoint().getY(); + int worldMinY = world.getMinimumPoint().y(); + int worldMaxY = world.getMaximumPoint().y(); int x = searchPos.getBlockX(); int y = Math.max(worldMinY, searchPos.getBlockY()); @@ -202,7 +202,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { public void setOnGround(Location searchPos) { Extent world = searchPos.getExtent(); - int worldMinY = world.getMinimumPoint().getY(); + int worldMinY = world.getMinimumPoint().y(); int x = searchPos.getBlockX(); int y = Math.max(worldMinY, searchPos.getBlockY()); @@ -436,7 +436,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public Location getBlockOn() { final Location location = getLocation(); - return location.setPosition(location.setY(location.getY() - 1).toVector().floor()); + return location.setPosition(location.setY(location.y() - 1).toVector().floor()); } @Override 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 3d2a45642..6117c6850 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 @@ -504,8 +504,8 @@ public interface Extent extends InputExtent, OutputExtent { if (random.nextInt(100) > rarity) { continue; } - int x = (chunkPos.getBlockX() << 4) + random.nextInt(16); - int z = (chunkPos.getBlockZ() << 4) + random.nextInt(16); + int x = (chunkPos.x() << 4) + random.nextInt(16); + int z = (chunkPos.z() << 4) + random.nextInt(16); gen.spawn(random, x, z); } } @@ -534,9 +534,9 @@ public interface Extent extends InputExtent, OutputExtent { default boolean contains(int x, int y, int z) { BlockVector3 min = getMinimumPoint(); BlockVector3 max = getMaximumPoint(); - return min.getX() <= x && max.getX() >= x - && min.getY() <= y && max.getY() >= y - && min.getZ() <= z && max.getZ() >= z; + return min.x() <= x && max.x() >= x + && min.y() <= y && max.y() >= y + && min.z() <= z && max.z() >= z; } default void addOre( @@ -665,11 +665,11 @@ public interface Extent extends InputExtent, OutputExtent { } default int getMinY() { - return getMinimumPoint().getY(); + return getMinimumPoint().y(); } default int getMaxY() { - return getMaximumPoint().getY(); + return getMaximumPoint().y(); } /** @@ -832,9 +832,9 @@ public interface Extent extends InputExtent, OutputExtent { Vector3 center = region.getCenter(); Region centerRegion = new CuboidRegion( this instanceof World ? (World) this : null, // Causes clamping of Y range - BlockVector3.at(((int) center.getX()), ((int) center.getY()), ((int) center.getZ())), - BlockVector3.at(MathUtils.roundHalfUp(center.getX()), - center.getY(), MathUtils.roundHalfUp(center.getZ()) + BlockVector3.at(((int) center.x()), ((int) center.y()), ((int) center.z())), + BlockVector3.at(MathUtils.roundHalfUp(center.x()), + center.y(), MathUtils.roundHalfUp(center.z()) ) ); return setBlocks(centerRegion, pattern); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java index 58863920c..7393c7722 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java @@ -50,7 +50,7 @@ public interface InputExtent { * @return the block */ default BlockState getBlock(BlockVector3 position) { - return getBlock(position.getX(), position.getY(), position.getZ()); + return getBlock(position.x(), position.y(), position.z()); } //FAWE start @@ -65,7 +65,7 @@ public interface InputExtent { * @return the block */ default BaseBlock getFullBlock(BlockVector3 position) { - return getFullBlock(position.getX(), position.getY(), position.getZ()); + return getFullBlock(position.x(), position.y(), position.z()); } default BaseBlock getFullBlock(int x, int y, int z) { @@ -85,7 +85,7 @@ public interface InputExtent { */ @Deprecated default BiomeType getBiome(BlockVector2 position) { - return getBiomeType(position.getX(), 0, position.getZ()); + return getBiomeType(position.x(), 0, position.z()); } default BiomeType getBiomeType(int x, int y, int z) { @@ -126,7 +126,7 @@ public interface InputExtent { * @return the light level at the location */ default int getEmittedLight(BlockVector3 position) { - return getEmittedLight(position.getX(), position.getY(), position.getZ()); + return getEmittedLight(position.x(), position.y(), position.z()); } default int getEmittedLight(int x, int y, int z) { @@ -140,7 +140,7 @@ public interface InputExtent { * @return the sky light level at the location */ default int getSkyLight(MutableBlockVector3 position) { - return getSkyLight(position.getX(), position.getY(), position.getZ()); + return getSkyLight(position.x(), position.y(), position.z()); } default int getSkyLight(int x, int y, int z) { @@ -148,7 +148,7 @@ public interface InputExtent { } default int getBrightness(MutableBlockVector3 position) { - return getBrightness(position.getX(), position.getY(), position.getZ()); + return getBrightness(position.x(), position.y(), position.z()); } default int getBrightness(int x, int y, int z) { @@ -156,7 +156,7 @@ public interface InputExtent { } default int getOpacity(MutableBlockVector3 position) { - return getOpacity(position.getX(), position.getY(), position.getZ()); + return getOpacity(position.x(), position.y(), position.z()); } default int getOpacity(int x, int y, int z) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java index d90bce937..9346bf380 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java @@ -60,7 +60,7 @@ public interface OutputExtent { */ @Deprecated default > boolean setBlock(BlockVector3 position, T block) throws WorldEditException { - return setBlock(position.getX(), position.getY(), position.getZ(), block); + return setBlock(position.x(), position.y(), position.z(), block); } // The defaults need to remain for compatibility (the actual implementation still needs to override one of these) @@ -148,7 +148,7 @@ public interface OutputExtent { * @param value light level to set */ default void setBlockLight(BlockVector3 position, int value) { - setBlockLight(position.getX(), position.getY(), position.getZ(), value); + setBlockLight(position.x(), position.y(), position.z(), value); } default void setBlockLight(int x, int y, int z, int value) { @@ -161,7 +161,7 @@ public interface OutputExtent { * @param value light level to set */ default void setSkyLight(BlockVector3 position, int value) { - setSkyLight(position.getX(), position.getY(), position.getZ(), value); + setSkyLight(position.x(), position.y(), position.z(), value); } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index 7b6be41d2..b861dbd6b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -165,9 +165,9 @@ public class BlockArrayClipboard implements Clipboard { @Override public BlockState getBlock(BlockVector3 position) { if (region.contains(position)) { - int x = position.getBlockX() - offset.getX(); - int y = position.getBlockY() - offset.getY(); - int z = position.getBlockZ() - offset.getZ(); + int x = position.x() - offset.x(); + int y = position.y() - offset.y(); + int z = position.z() - offset.z(); return getParent().getBlock(x, y, z); } @@ -177,9 +177,9 @@ public class BlockArrayClipboard implements Clipboard { @Override public BaseBlock getFullBlock(BlockVector3 position) { if (region.contains(position)) { - int x = position.getBlockX() - offset.getX(); - int y = position.getBlockY() - offset.getY(); - int z = position.getBlockZ() - offset.getZ(); + int x = position.x() - offset.x(); + int y = position.y() - offset.y(); + int z = position.z() - offset.z(); return getParent().getFullBlock(x, y, z); } return BlockTypes.AIR.getDefaultState().toBaseBlock(); @@ -189,9 +189,9 @@ public class BlockArrayClipboard implements Clipboard { public > boolean setBlock(BlockVector3 position, B block) throws WorldEditException { if (region.contains(position)) { //FAWE - get points - final int x = position.getBlockX(); - final int y = position.getBlockY(); - final int z = position.getBlockZ(); + final int x = position.x(); + final int y = position.y(); + final int z = position.z(); return setBlock(x, y, z, block); //FAWE end } @@ -201,22 +201,22 @@ public class BlockArrayClipboard implements Clipboard { //FAWE start @Override public boolean setTile(int x, int y, int z, CompoundTag tag) { - x -= offset.getX(); - y -= offset.getY(); - z -= offset.getZ(); + x -= offset.x(); + y -= offset.y(); + z -= offset.z(); return getParent().setTile(x, y, z, tag); } public boolean setTile(BlockVector3 position, CompoundTag tag) { - return setTile(position.getX(), position.getY(), position.getZ(), tag); + return setTile(position.x(), position.y(), position.z(), tag); } @Override public > boolean setBlock(int x, int y, int z, B block) throws WorldEditException { - x -= offset.getX(); - y -= offset.getY(); - z -= offset.getZ(); + x -= offset.x(); + y -= offset.y(); + z -= offset.z(); return parent.setBlock(x, y, z, block); } @@ -230,25 +230,25 @@ public class BlockArrayClipboard implements Clipboard { if (!region.contains(position)) { return null; } - int x = position.getBlockX() - offset.getX(); - int y = position.getBlockY() - offset.getY(); - int z = position.getBlockZ() - offset.getZ(); + int x = position.x() - offset.x(); + int y = position.y() - offset.y(); + int z = position.z() - offset.z(); return getParent().getBiomeType(x, y, z); } @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { - int x = position.getBlockX() - offset.getX(); - int y = position.getBlockY() - offset.getY(); - int z = position.getBlockZ() - offset.getZ(); + int x = position.x() - offset.x(); + int y = position.y() - offset.y(); + int z = position.z() - offset.z(); return getParent().setBiome(x, y, z, biome); } @Override public boolean setBiome(int x, int y, int z, BiomeType biome) { - x -= offset.getX(); - y -= offset.getY(); - z -= offset.getZ(); + x -= offset.x(); + y -= offset.y(); + z -= offset.z(); return getParent().setBiome(x, y, z, biome); } @@ -262,9 +262,9 @@ public class BlockArrayClipboard implements Clipboard { ClipboardEntity ce = (ClipboardEntity) e; Location oldloc = ce.getLocation(); Location loc = new Location(oldloc.getExtent(), - oldloc.getX() + offset.getBlockX(), - oldloc.getY() + offset.getBlockY(), - oldloc.getZ() + offset.getBlockZ(), + oldloc.x() + offset.x(), + oldloc.y() + offset.y(), + oldloc.z() + offset.z(), oldloc.getYaw(), oldloc.getPitch() ); return new ClipboardEntity(loc, ce.entity); @@ -281,9 +281,9 @@ public class BlockArrayClipboard implements Clipboard { ClipboardEntity ce = (ClipboardEntity) e; Location oldloc = ce.getLocation(); Location loc = new Location(oldloc.getExtent(), - oldloc.getX() + offset.getBlockX(), - oldloc.getY() + offset.getBlockY(), - oldloc.getZ() + offset.getBlockZ(), + oldloc.x() + offset.x(), + oldloc.y() + offset.y(), + oldloc.z() + offset.z(), oldloc.getYaw(), oldloc.getPitch() ); return new ClipboardEntity(loc, ce.entity); @@ -296,9 +296,9 @@ public class BlockArrayClipboard implements Clipboard { @Nullable public Entity createEntity(Location location, BaseEntity entity) { Location l = new Location(location.getExtent(), - location.getX() - offset.getBlockX(), - location.getY() - offset.getBlockY(), - location.getZ() - offset.getBlockZ(), + location.x() - offset.x(), + location.y() - offset.y(), + location.z() - offset.z(), location.getYaw(), location.getPitch() ); return getParent().createEntity(l, entity); @@ -308,9 +308,9 @@ public class BlockArrayClipboard implements Clipboard { @Nullable public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { Location l = new Location(location.getExtent(), - location.getX() - offset.getBlockX(), - location.getY() - offset.getBlockY(), - location.getZ() - offset.getBlockZ(), + location.x() - offset.x(), + location.y() - offset.y(), + location.z() - offset.z(), location.getYaw(), location.getPitch() ); return getParent().createEntity(l, entity, uuid); @@ -318,33 +318,33 @@ public class BlockArrayClipboard implements Clipboard { @Override public void removeEntity(int x, int y, int z, UUID uuid) { - x -= offset.getX(); - y -= offset.getY(); - z -= offset.getZ(); + x -= offset.x(); + y -= offset.y(); + z -= offset.z(); getParent().removeEntity(x, y, z, uuid); } @Override public BlockState getBlock(int x, int y, int z) { - x -= offset.getX(); - y -= offset.getY(); - z -= offset.getZ(); + x -= offset.x(); + y -= offset.y(); + z -= offset.z(); return getParent().getBlock(x, y, z); } @Override public BaseBlock getFullBlock(int x, int y, int z) { - x -= offset.getX(); - y -= offset.getY(); - z -= offset.getZ(); + x -= offset.x(); + y -= offset.y(); + z -= offset.z(); return getParent().getFullBlock(x, y, z); } @Override public BiomeType getBiomeType(int x, int y, int z) { - x -= offset.getX(); - y -= offset.getY(); - z -= offset.getZ(); + x -= offset.x(); + y -= offset.y(); + z -= offset.z(); return getParent().getBiomeType(x, y, z); } @@ -359,7 +359,7 @@ public class BlockArrayClipboard implements Clipboard { public Iterator iterator2d() { MutableBlockVector2 mutable = new MutableBlockVector2(); return Iterators.transform(getParent().iterator2d(), input -> - mutable.setComponents(input.getX() + offset.getX(), input.getZ() + offset.getZ())); + mutable.setComponents(input.x() + offset.x(), input.z() + offset.z())); } @Override @@ -409,7 +409,7 @@ public class BlockArrayClipboard implements Clipboard { private final float pitch; public ClipboardEntity(Location loc, BaseEntity entity) { - this((Clipboard) loc.getExtent(), loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch(), entity); + this((Clipboard) loc.getExtent(), loc.x(), loc.y(), loc.z(), loc.getYaw(), loc.getPitch(), entity); } public ClipboardEntity(Clipboard clipboard, double x, double y, double z, float yaw, float pitch, BaseEntity entity) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java index 76e866c33..d52fd1056 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java @@ -163,15 +163,15 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl void removeEntity(Entity entity); default int getWidth() { - return getDimensions().getBlockX(); + return getDimensions().x(); } default int getHeight() { - return getDimensions().getBlockY(); + return getDimensions().y(); } default int getLength() { - return getDimensions().getBlockZ(); + return getDimensions().z(); } default int getArea() { @@ -380,17 +380,17 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl final BlockVector3 origin = this.getOrigin(); // To must be relative to the clipboard origin ( player location - clipboard origin ) (as the locations supplied are relative to the world origin) - final int relx = to.getBlockX() - origin.getBlockX(); - final int rely = to.getBlockY() - origin.getBlockY(); - final int relz = to.getBlockZ() - origin.getBlockZ(); + final int relx = to.x() - origin.x(); + final int rely = to.y() - origin.y(); + final int relz = to.z() - origin.z(); pasteBiomes &= Clipboard.this.hasBiomes(); for (BlockVector3 pos : this) { BaseBlock block = pos.getFullBlock(this); - int xx = pos.getX() + relx; - int yy = pos.getY() + rely; - int zz = pos.getZ() + relz; + int xx = pos.x() + relx; + int yy = pos.y() + rely; + int zz = pos.z() + relz; if (pasteBiomes) { extent.setBiome(xx, yy, zz, pos.getBiome(this)); } @@ -400,9 +400,9 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl extent.setBlock(xx, yy, zz, block); } // Entity offset is the paste location subtract the clipboard origin (entity's location is already relative to the world origin) - final int entityOffsetX = to.getBlockX() - origin.getBlockX(); - final int entityOffsetY = to.getBlockY() - origin.getBlockY(); - final int entityOffsetZ = to.getBlockZ() - origin.getBlockZ(); + final int entityOffsetX = to.x() - origin.x(); + final int entityOffsetY = to.y() - origin.y(); + final int entityOffsetZ = to.z() - origin.z(); // entities if (pasteEntities) { for (Entity entity : this.getEntities()) { @@ -412,8 +412,8 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl continue; } Location pos = entity.getLocation(); - Location newPos = new Location(pos.getExtent(), pos.getX() + entityOffsetX, - pos.getY() + entityOffsetY, pos.getZ() + entityOffsetZ, pos.getYaw(), + Location newPos = new Location(pos.getExtent(), pos.x() + entityOffsetX, + pos.y() + entityOffsetY, pos.z() + entityOffsetZ, pos.getYaw(), pos.getPitch() ); extent.createEntity(newPos, entity.getState()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardWriter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardWriter.java index b7cf7a050..d3420f658 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardWriter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardWriter.java @@ -50,9 +50,9 @@ public interface ClipboardWriter extends Closeable { //FAWE start default 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())); + list.add(new DoubleTag(vector.x())); + list.add(new DoubleTag(vector.y())); + list.add(new DoubleTag(vector.z())); return new ListTag(DoubleTag.class, list); } 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 83d8c3007..a140b666a 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 @@ -263,9 +263,9 @@ public class SpongeSchematicReader extends NBTSchematicReader { int[] pos = requireTag(tileEntity, "Pos", IntArrayTag.class).getValue(); final BlockVector3 pt = BlockVector3.at(pos[0], pos[1], pos[2]); Map values = Maps.newHashMap(tileEntity); - values.put("x", new IntTag(pt.getBlockX())); - values.put("y", new IntTag(pt.getBlockY())); - values.put("z", new IntTag(pt.getBlockZ())); + values.put("x", new IntTag(pt.x())); + values.put("y", new IntTag(pt.y())); + values.put("z", new IntTag(pt.z())); //FAWE start - support old, corrupt schematics Tag id = values.get("Id"); if (id == null) { @@ -378,7 +378,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { palette.put(((IntTag) idTag).getValue(), biome); } - int width = clipboard.getDimensions().getX(); + int width = clipboard.getDimensions().x(); byte[] biomes = dataTag.getValue(); int biomeIndex = 0; 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 2a10e9f4b..24860dd3c 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 @@ -117,9 +117,9 @@ public class SpongeSchematicWriter implements ClipboardWriter { WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion())); Map metadata = new HashMap<>(); - metadata.put("WEOffsetX", new IntTag(offset.getBlockX())); - metadata.put("WEOffsetY", new IntTag(offset.getBlockY())); - metadata.put("WEOffsetZ", new IntTag(offset.getBlockZ())); + metadata.put("WEOffsetX", new IntTag(offset.x())); + metadata.put("WEOffsetY", new IntTag(offset.y())); + metadata.put("WEOffsetZ", new IntTag(offset.z())); metadata.put("FAWEVersion", new IntTag(Fawe.instance().getVersion().build)); schematic.put("Metadata", new CompoundTag(metadata)); @@ -130,9 +130,9 @@ public class SpongeSchematicWriter implements ClipboardWriter { // The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin' schematic.put("Offset", new IntArrayTag(new int[]{ - min.getBlockX(), - min.getBlockY(), - min.getBlockZ(), + min.x(), + min.y(), + min.z(), })); int paletteMax = 0; @@ -143,11 +143,11 @@ public class SpongeSchematicWriter implements ClipboardWriter { ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * height * length); for (int y = 0; y < height; y++) { - int y0 = min.getBlockY() + y; + int y0 = min.y() + y; for (int z = 0; z < length; z++) { - int z0 = min.getBlockZ() + z; + int z0 = min.z() + z; for (int x = 0; x < width; x++) { - int x0 = min.getBlockX() + x; + int x0 = min.x() + x; BlockVector3 point = BlockVector3.at(x0, y0, z0); BaseBlock block = clipboard.getFullBlock(point); if (block.getNbtData() != null) { @@ -217,10 +217,10 @@ public class SpongeSchematicWriter implements ClipboardWriter { Map palette = new HashMap<>(); for (int z = 0; z < length; z++) { - int z0 = min.getBlockZ() + z; + int z0 = min.z() + z; for (int x = 0; x < width; x++) { - int x0 = min.getBlockX() + x; - BlockVector3 pt = BlockVector3.at(x0, min.getBlockY(), z0); + int x0 = min.x() + x; + BlockVector3 pt = BlockVector3.at(x0, min.y(), z0); BiomeType biome = clipboard.getBiome(pt); String biomeKey = biome.getId(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java index ff516e4c9..18e69c7a0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/inventory/BlockBagExtent.java @@ -104,7 +104,7 @@ public class BlockBagExtent extends AbstractDelegateExtent { @Override public > boolean setBlock(BlockVector3 position, B block) throws WorldEditException { - return setBlock(position.getX(), position.getY(), position.getZ(), block); + return setBlock(position.x(), position.y(), position.z(), block); } @Override 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 f22d7036d..d9effa512 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 @@ -391,9 +391,9 @@ public class BlockTransformExtent extends ResettableExtent { if (direction != null) { Vector3 applyAbsolute = transform.apply(direction.toVector()); Vector3 applyOrigin = transform.apply(Vector3.ZERO); - applyAbsolute.mutX(applyAbsolute.getX() - applyOrigin.getX()); - applyAbsolute.mutY(applyAbsolute.getY() - applyOrigin.getY()); - applyAbsolute.mutZ(applyAbsolute.getZ() - applyOrigin.getZ()); + applyAbsolute.mutX(applyAbsolute.x() - applyOrigin.x()); + applyAbsolute.mutY(applyAbsolute.y() - applyOrigin.y()); + applyAbsolute.mutZ(applyAbsolute.z() - applyOrigin.z()); Direction newDirection = Direction.findClosest( applyAbsolute, diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java index bc498711b..1161779d9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java @@ -63,7 +63,7 @@ public class DataValidatorExtent extends AbstractDelegateExtent { @Override public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { - final int y = location.getBlockY(); + final int y = location.y(); final BlockType type = block.getBlockType(); if (y < minY || y > maxY) { return false; @@ -79,7 +79,7 @@ public class DataValidatorExtent extends AbstractDelegateExtent { @Override public boolean setBiome(BlockVector3 location, BiomeType biome) { - final int y = location.getBlockY(); + final int y = location.y(); if (y < minY || y > maxY) { return false; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SideEffectExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SideEffectExtent.java index 5a90aebbb..413bd31bf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SideEffectExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SideEffectExtent.java @@ -88,7 +88,7 @@ public class SideEffectExtent extends AbstractDelegateExtent { @Override public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { if (sideEffectSet.getState(SideEffect.LIGHTING) == SideEffect.State.DELAYED) { - dirtyChunks.add(BlockVector2.at(location.getBlockX() >> 4, location.getBlockZ() >> 4)); + dirtyChunks.add(BlockVector2.at(location.x() >> 4, location.z() >> 4)); } if (postEditSimulation) { positions.put(location, world.getBlock(location)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/BiomeReplace.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/BiomeReplace.java index 6ae4ad2ec..90d7f31cf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/BiomeReplace.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/BiomeReplace.java @@ -70,7 +70,7 @@ public class BiomeReplace implements FlatRegionFunction, RegionFunction { @Deprecated public boolean apply(BlockVector2 position) throws WorldEditException { boolean success = false; - for (int y = extent.getMinimumPoint().getY(); y <= extent.getMaximumPoint().getY(); y++) { + for (int y = extent.getMinimumPoint().y(); y <= extent.getMaximumPoint().y(); y++) { success |= apply(position.toBlockVector3(y)); } return success; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/ExtentBiomeCopy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/ExtentBiomeCopy.java index 076c1f561..5643da36a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/ExtentBiomeCopy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/ExtentBiomeCopy.java @@ -102,7 +102,7 @@ public class ExtentBiomeCopy implements FlatRegionFunction, RegionFunction { @Deprecated public boolean apply(BlockVector2 position) throws WorldEditException { boolean success = false; - for (int y = destination.getMinimumPoint().getY(); y <= destination.getMaximumPoint().getY(); y++) { + for (int y = destination.getMinimumPoint().y(); y <= destination.getMaximumPoint().y(); y++) { success |= apply(position.toBlockVector3(y)); } return success; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/SnowSimulator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/SnowSimulator.java index c84fcc67a..4027220b2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/SnowSimulator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/SnowSimulator.java @@ -105,7 +105,7 @@ public class SnowSimulator implements LayerFunction { // Can't put snow this far up - if (position.getBlockY() == this.extent.getMaximumPoint().getBlockY()) { + if (position.y() == this.extent.getMaximumPoint().y()) { return false; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java index fa3ef1dc4..149464bef 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java @@ -206,9 +206,9 @@ public class ExtentEntityCopy implements EntityFunction { BlockVector3 newLeash = transform.apply(tilePosition.subtract(from)).add(to).toBlockPoint(); return new BaseEntity(state.getType(), tag.createBuilder() .put("Leash", leashCompound.createBuilder() - .putInt("X", newLeash.getBlockX()) - .putInt("Y", newLeash.getBlockY()) - .putInt("Z", newLeash.getBlockZ()) + .putInt("X", newLeash.x()) + .putInt("Y", newLeash.y()) + .putInt("Z", newLeash.z()) .build() ).build()); } @@ -226,9 +226,9 @@ public class ExtentEntityCopy implements EntityFunction { BlockVector3 newTilePosition = transform.apply(tilePosition.subtract(from)).add(to).toBlockPoint(); CompoundTagBuilder builder = tag.createBuilder() - .putInt("TileX", newTilePosition.getBlockX()) - .putInt("TileY", newTilePosition.getBlockY()) - .putInt("TileZ", newTilePosition.getBlockZ()); + .putInt("TileX", newTilePosition.x()) + .putInt("TileY", newTilePosition.y()) + .putInt("TileZ", newTilePosition.z()); if (hasFacing) { boolean isPainting = state.getType() == EntityTypes.PAINTING; // Paintings have different facing values diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/ApplyLayer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/ApplyLayer.java index 88e3218c0..c7ecc1207 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/ApplyLayer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/ApplyLayer.java @@ -53,8 +53,8 @@ public class ApplyLayer implements Contextual { return new LayerVisitor( localRegion, - localRegion.getMinimumPoint().getY(), - localRegion.getMaximumPoint().getY(), + localRegion.getMinimumPoint().y(), + localRegion.getMaximumPoint().y(), function.createFromContext(context), //FAWE start - provide extent for preloading context.getDestination() diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java index 115c05044..b4ccd0a55 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java @@ -141,13 +141,13 @@ public class Deform implements Contextual { zero = max.add(min).multiply(0.5); unit = max.subtract(zero); - if (unit.getX() == 0) { + if (unit.x() == 0) { unit = unit.withX(1.0); } - if (unit.getY() == 0) { + if (unit.y() == 0) { unit = unit.withY(1.0); } - if (unit.getZ() == 0) { + if (unit.z() == 0) { unit = unit.withZ(1.0); } break; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java index dfe1841d4..808465416 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java @@ -48,7 +48,7 @@ public class BoundedHeightMask extends AbstractMask { @Override public boolean test(BlockVector3 vector) { - return vector.getY() >= minY && vector.getY() <= maxY; + return vector.y() >= minY && vector.y() <= maxY; } @Nullable 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 1b95057ba..e5647332e 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 @@ -73,10 +73,10 @@ public class ExpressionMask extends AbstractMask { ((WorldEditExpressionEnvironment) expression.getEnvironment()).setCurrentBlock(vector.toVector3()); } if (timeout == null) { - return expression.evaluate(vector.getX(), vector.getY(), vector.getZ()) > 0; + return expression.evaluate(vector.x(), vector.y(), vector.z()) > 0; } else { return expression.evaluate( - new double[]{vector.getX(), vector.getY(), vector.getZ()}, + new double[]{vector.x(), vector.y(), vector.z()}, timeout.getAsInt() ) > 0; } 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 0d2854b7c..7d5e22e99 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 @@ -63,9 +63,9 @@ public class ExpressionMask2D extends AbstractMask2D { public boolean test(BlockVector2 vector) { try { if (timeout == null) { - return expression.evaluate(vector.getX(), 0, vector.getZ()) > 0; + return expression.evaluate(vector.x(), 0, vector.z()) > 0; } else { - return expression.evaluate(timeout.getAsInt(), vector.getX(), 0, vector.getZ()) > 0; + return expression.evaluate(timeout.getAsInt(), vector.x(), 0, vector.z()) > 0; } } catch (EvaluationException e) { return false; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java index 684148505..d0a016639 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java @@ -97,7 +97,7 @@ public class NoiseFilter extends AbstractMask { @Override public boolean test(BlockVector3 vector) { //FAWE start - mutable - return noiseGenerator.noise(mutable.setComponents(vector.getX(), vector.getZ(), vector.getZ())) <= density; + return noiseGenerator.noise(mutable.setComponents(vector.x(), vector.z(), vector.z())) <= density; //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java index 2c809ada4..39eda315b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java @@ -116,7 +116,7 @@ public class OffsetMask extends AbstractMask { public boolean test(BlockVector3 vector) { //FAWE start - ignore resultant position outside world height range BlockVector3 testPos = vector.add(offset); - if (testPos.getBlockY() < minY || testPos.getBlockY() > maxY) { + if (testPos.y() < minY || testPos.y() > maxY) { return false; } return getMask().test(testPos); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask2D.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask2D.java index 3e70c9ddd..f08811513 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask2D.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask2D.java @@ -89,13 +89,13 @@ public class OffsetMask2D extends AbstractMask2D { //FAWE start @Override public boolean test(BlockVector2 vector) { - mutableBlockVector2.setComponents(vector.getX() + offset.getX(), vector.getZ() + offset.getZ()); + mutableBlockVector2.setComponents(vector.x() + offset.x(), vector.z() + offset.z()); return getMask().test(mutableBlockVector2); } @Override public Mask2D copy2D() { - return new OffsetMask2D(mask.copy2D(), BlockVector2.at(offset.getX(), offset.getZ())); + return new OffsetMask2D(mask.copy2D(), BlockVector2.at(offset.x(), offset.z())); } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/BackwardsExtentBlockCopy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/BackwardsExtentBlockCopy.java index f766cf8d7..75018d96d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/BackwardsExtentBlockCopy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/BackwardsExtentBlockCopy.java @@ -52,9 +52,9 @@ public class BackwardsExtentBlockCopy extends RegionVisitor implements Operation BlockVector3 max = BlockVector3.at(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); BlockVector3 pos1 = region.getMinimumPoint(); BlockVector3 pos2 = region.getMaximumPoint(); - for (int x : new int[]{pos1.getBlockX(), pos2.getBlockX()}) { - for (int y : new int[]{pos1.getBlockY(), pos2.getBlockY()}) { - for (int z : new int[]{pos1.getBlockZ(), pos2.getBlockZ()}) { + for (int x : new int[]{pos1.x(), pos2.x()}) { + for (int y : new int[]{pos1.y(), pos2.y()}) { + for (int z : new int[]{pos1.z(), pos2.z()}) { BlockVector3 pt = transform(transform, BlockVector3.at(x, y, z)); min = min.getMinimum(pt); max = max.getMaximum(pt); @@ -65,13 +65,13 @@ public class BackwardsExtentBlockCopy extends RegionVisitor implements Operation } private BlockVector3 transform(Transform transform, BlockVector3 pt) { - mutV3.mutX(((pt.getBlockX() - origin.getBlockX()))); - mutV3.mutY(((pt.getBlockY() - origin.getBlockY()))); - mutV3.mutZ(((pt.getBlockZ() - origin.getBlockZ()))); + mutV3.mutX(((pt.x() - origin.x()))); + mutV3.mutY(((pt.y() - origin.y()))); + mutV3.mutZ(((pt.z() - origin.z()))); Vector3 tmp = transform.apply(mutV3); - mutBV3.mutX((tmp.getBlockX() + origin.getBlockX())); - mutBV3.mutY((tmp.getBlockY() + origin.getBlockY())); - mutBV3.mutZ((tmp.getBlockZ() + origin.getBlockZ())); + mutBV3.mutX((tmp.getBlockX() + origin.x())); + mutBV3.mutY((tmp.getBlockY() + origin.y())); + mutBV3.mutZ((tmp.getBlockZ() + origin.z())); return mutBV3; } 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 99ee125ed..f98d5f924 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 @@ -306,9 +306,9 @@ public class ForwardExtentCopy implements Operation { if (!translation.equals(BlockVector3.ZERO)) { finalDest = new BlockTranslateExtent( finalDest, - translation.getBlockX(), - translation.getBlockY(), - translation.getBlockZ() + translation.x(), + translation.y(), + translation.z() ); } //FAWE end @@ -349,21 +349,21 @@ public class ForwardExtentCopy implements Operation { if (sourceFunction != null) { BlockVector3 disAbs = translation.abs(); BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1); - boolean overlap = (disAbs.getBlockX() < size.getBlockX() && disAbs.getBlockY() < size.getBlockY() && disAbs.getBlockZ() < size - .getBlockZ()); + boolean overlap = (disAbs.x() < size.x() && disAbs.y() < size.y() && disAbs.z() < size + .z()); RegionFunction copySrcFunc = sourceFunction; if (overlap && translation.length() != 0) { - int x = translation.getBlockX(); - int y = translation.getBlockY(); - int z = translation.getBlockZ(); + int x = translation.x(); + int y = translation.y(); + int z = translation.z(); maskFunc = position -> { BlockVector3 bv = BlockVector3.at( - position.getBlockX() + x, - position.getBlockY() + y, - position.getBlockZ() + z + position.x() + x, + position.y() + y, + position.z() + z ); if (region.contains(bv)) { return sourceFunction.apply(bv); @@ -373,9 +373,9 @@ public class ForwardExtentCopy implements Operation { copySrcFunc = position -> { BlockVector3 bv = BlockVector3.at( - position.getBlockX() - x, - position.getBlockY() - y, - position.getBlockZ() - z + position.x() - x, + position.y() - y, + position.z() - z ); if (!region.contains(bv)) { return sourceFunction.apply(position); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java index c45629e5f..bc13fe4de 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java @@ -107,12 +107,12 @@ public class RandomPattern extends AbstractPattern { @Override public BaseBlock applyBlock(BlockVector3 position) { - return collection.next(position.getBlockX(), position.getBlockY(), position.getBlockZ()).applyBlock(position); + return collection.next(position.x(), position.y(), position.z()).applyBlock(position); } @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - return collection.next(get.getBlockX(), get.getBlockY(), get.getBlockZ()).apply(extent, get, set); + return collection.next(get.x(), get.y(), get.z()).apply(extent, get, set); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java index 490c47cf2..ed62f92d8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java @@ -88,9 +88,9 @@ public class RepeatingExtentPattern extends AbstractExtentPattern { @Override public BaseBlock applyBlock(BlockVector3 position) { //FAWE start - calculate offset - int x = Math.floorMod(position.getBlockX() + offset.getBlockX(), size.getBlockX()) + origin.getBlockX(); - int y = Math.floorMod(position.getBlockY() + offset.getBlockY(), size.getBlockY()) + origin.getBlockY(); - int z = Math.floorMod(position.getBlockZ() + offset.getBlockZ(), size.getBlockZ()) + origin.getBlockZ(); + int x = Math.floorMod(position.x() + offset.x(), size.x()) + origin.x(); + int y = Math.floorMod(position.y() + offset.y(), size.y()) + origin.y(); + int z = Math.floorMod(position.z() + offset.z(), size.z()) + origin.z(); //FAWE end return getExtent().getFullBlock(x, y, z); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java index 7f3e5da63..796f02700 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java @@ -305,10 +305,10 @@ public abstract class BreadthFirstSearch implements Operation { if (loadCount > Settings.settings().QUEUE.PRELOAD_CHUNK_COUNT) { break outer; } - int x = from.getBlockX() + direction.getBlockX(); - int z = from.getBlockZ() + direction.getBlockX(); + int x = from.x() + direction.x(); + int z = from.z() + direction.x(); if (cx != (cx = x >> 4) || cz != (cz = z >> 4)) { - int y = from.getBlockY() + direction.getBlockY(); + int y = from.y() + direction.y(); if (y < singleQueue.getMinY() || y > singleQueue.getMaxY()) { continue; } @@ -320,7 +320,7 @@ public abstract class BreadthFirstSearch implements Operation { } } for (BlockVector3 chunk : chunkLoadSet) { - singleQueue.addChunkLoad(chunk.getBlockX(), chunk.getBlockZ()); + singleQueue.addChunkLoad(chunk.x(), chunk.z()); } } for (BlockVector3 from : queue) { @@ -329,12 +329,12 @@ public abstract class BreadthFirstSearch implements Operation { } for (int i = 0, j = 0; i < dirs.length && j < maxBranch; i++) { BlockVector3 direction = dirs[i]; - int y = from.getBlockY() + direction.getY(); + int y = from.y() + direction.y(); if (y < minY || y > maxY) { continue; } - int x = from.getBlockX() + direction.getX(); - int z = from.getBlockZ() + direction.getZ(); + int x = from.x() + direction.x(); + int z = from.z() + direction.z(); if (!visited.contains(x, y, z)) { if (isVisitable(from, mutable.setComponents(x, y, z))) { j++; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java index f8204b085..2e5f07736 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java @@ -102,8 +102,8 @@ public class DownwardVisitor extends RecursiveVisitor { @Override protected boolean isVisitable(BlockVector3 from, BlockVector3 to) { - int fromY = from.getBlockY(); - return (fromY == baseY || to.subtract(from).getBlockY() < 0) && super.isVisitable(from, to); + int fromY = from.y(); + return (fromY == baseY || to.subtract(from).y() < 0) && super.isVisitable(from, to); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java index ff6b67e03..5ed98c354 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java @@ -111,8 +111,8 @@ public class RegionVisitor implements Operation { while (trailIter.hasNext()) { BlockVector3 pt = trailIter.next(); apply(pt); - int cx = pt.getBlockX() >> 4; - int cz = pt.getBlockZ() >> 4; + int cx = pt.x() >> 4; + int cz = pt.z() >> 4; if (cx != lastTrailChunkX || cz != lastTrailChunkZ) { lastTrailChunkX = cx; lastTrailChunkZ = cz; @@ -128,8 +128,8 @@ public class RegionVisitor implements Operation { lead: for (int count = 0; count < amount; ) { BlockVector3 v = leadIter.next(); - int vcx = v.getBlockX() >> 4; - int vcz = v.getBlockZ() >> 4; + int vcx = v.x() >> 4; + int vcz = v.z() >> 4; if (vcx != lastLeadChunkX || vcz != lastLeadChunkZ) { lastLeadChunkX = vcx; lastLeadChunkZ = vcz; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ArrayListHistory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ArrayListHistory.java index ff624e81e..1bad79fb9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ArrayListHistory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ArrayListHistory.java @@ -83,7 +83,7 @@ public class ArrayListHistory implements ChangeSet { if (change instanceof BlockChange) { BlockChange blockChange = (BlockChange) change; BlockVector3 pos = blockChange.getPosition(); - summary.add(pos.getX(), pos.getZ(), blockChange.getCurrent().getOrdinal()); + summary.add(pos.x(), pos.z(), blockChange.getCurrent().getOrdinal()); } } return summary; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeleter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeleter.java index e4dcd99ab..1c88a1f2d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeleter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeleter.java @@ -54,7 +54,7 @@ public final class ChunkDeleter { private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Comparator chunkSorter = Comparator.comparing( - pos -> (pos.getBlockX() & 31) + (pos.getBlockZ() & 31) * 32 + pos -> (pos.x() & 31) + (pos.z() & 31) * 32 ); private static final Gson chunkDeleterGson = new GsonBuilder() @@ -182,15 +182,15 @@ public final class ChunkDeleter { int startZ = regZ << 5; int endZ = (regZ << 5) + 31; - int minX = Math.max(Math.min(startX, endX), minChunk.getBlockX()); - int minZ = Math.max(Math.min(startZ, endZ), minChunk.getBlockZ()); - int maxX = Math.min(Math.max(startX, endX), maxChunk.getBlockX()); - int maxZ = Math.min(Math.max(startZ, endZ), maxChunk.getBlockZ()); + int minX = Math.max(Math.min(startX, endX), minChunk.x()); + int minZ = Math.max(Math.min(startZ, endZ), minChunk.z()); + int maxX = Math.min(Math.max(startX, endX), maxChunk.x()); + int maxZ = Math.min(Math.max(startZ, endZ), maxChunk.z()); Stream stream = Stream.iterate( BlockVector2.at(minX, minZ), bv2 -> { - int nextX = bv2.getBlockX(); - int nextZ = bv2.getBlockZ(); + int nextX = bv2.x(); + int nextZ = bv2.z(); if (++nextX > maxX) { nextX = minX; if (++nextZ > maxZ) { @@ -295,8 +295,8 @@ public final class ChunkDeleter { @Override public void write(JsonWriter out, BlockVector2 value) throws IOException { out.beginArray(); - out.value(value.getBlockX()); - out.value(value.getBlockZ()); + out.value(value.x()); + out.value(value.z()); out.endArray(); } @@ -317,8 +317,8 @@ public final class ChunkDeleter { private final int z; RegionFilePos(BlockVector2 chunk) { - this.x = chunk.getBlockX() >> 5; - this.z = chunk.getBlockZ() >> 5; + this.x = chunk.x() >> 5; + this.z = chunk.z() >> 5; } RegionFilePos(int regX, int regZ) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeletionInfo.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeletionInfo.java index 13b9d3847..ffcb5f885 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeletionInfo.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeletionInfo.java @@ -45,7 +45,7 @@ public class ChunkDeletionInfo { return chunks.size(); } final BlockVector2 dist = maxChunk.subtract(minChunk).add(1, 1); - return dist.getBlockX() * dist.getBlockZ(); + return dist.x() * dist.z(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/RegionAccess.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/RegionAccess.java index 80eb6989e..7c545040e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/RegionAccess.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/RegionAccess.java @@ -57,8 +57,8 @@ class RegionAccess implements AutoCloseable { } private static int indexChunk(BlockVector2 pos) { - int x = pos.getBlockX() & 31; - int z = pos.getBlockZ() & 31; + int x = pos.x() & 31; + int z = pos.z() & 31; return x + z * 32; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/SelectionCylinderEvent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/SelectionCylinderEvent.java index b9cf79fe0..4150f9a5c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/SelectionCylinderEvent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/SelectionCylinderEvent.java @@ -42,11 +42,11 @@ public class SelectionCylinderEvent implements CUIEvent { @Override public String[] getParameters() { return new String[]{ - String.valueOf(pos.getBlockX()), - String.valueOf(pos.getBlockY()), - String.valueOf(pos.getBlockZ()), - String.valueOf(radius.getX()), - String.valueOf(radius.getZ()) + String.valueOf(pos.x()), + String.valueOf(pos.y()), + String.valueOf(pos.z()), + String.valueOf(radius.x()), + String.valueOf(radius.z()) }; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/SelectionEllipsoidPointEvent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/SelectionEllipsoidPointEvent.java index 3bf609b1b..4e0131329 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/SelectionEllipsoidPointEvent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/SelectionEllipsoidPointEvent.java @@ -40,9 +40,9 @@ public class SelectionEllipsoidPointEvent implements CUIEvent { public String[] getParameters() { return new String[]{ String.valueOf(id), - String.valueOf(pos.getBlockX()), - String.valueOf(pos.getBlockY()), - String.valueOf(pos.getBlockZ()) + String.valueOf(pos.x()), + String.valueOf(pos.y()), + String.valueOf(pos.z()) }; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPoint2DEvent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPoint2DEvent.java index f27eda25c..f01c240a2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPoint2DEvent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPoint2DEvent.java @@ -32,30 +32,30 @@ public class SelectionPoint2DEvent implements CUIEvent { @Deprecated public SelectionPoint2DEvent(int id, BlockVector2 pos, int area) { this.id = id; - this.blockX = pos.getX(); - this.blockZ = pos.getZ(); + this.blockX = pos.x(); + this.blockZ = pos.z(); this.area = area; } @Deprecated public SelectionPoint2DEvent(int id, BlockVector3 pos, int area) { this.id = id; - this.blockX = pos.getX(); - this.blockZ = pos.getZ(); + this.blockX = pos.x(); + this.blockZ = pos.z(); this.area = area; } public SelectionPoint2DEvent(int id, BlockVector2 pos, long area) { this.id = id; - this.blockX = pos.getX(); - this.blockZ = pos.getZ(); + this.blockX = pos.x(); + this.blockZ = pos.z(); this.area = area; } public SelectionPoint2DEvent(int id, BlockVector3 pos, long area) { this.id = id; - this.blockX = pos.getX(); - this.blockZ = pos.getZ(); + this.blockX = pos.x(); + this.blockZ = pos.z(); this.area = area; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPointEvent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPointEvent.java index 1ee2e466d..42718c7ae 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPointEvent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/SelectionPointEvent.java @@ -49,9 +49,9 @@ public class SelectionPointEvent implements CUIEvent { public String[] getParameters() { return new String[]{ String.valueOf(id), - String.valueOf(pos.getBlockX()), - String.valueOf(pos.getBlockY()), - String.valueOf(pos.getBlockZ()), + String.valueOf(pos.x()), + String.valueOf(pos.y()), + String.valueOf(pos.z()), String.valueOf(area) }; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java index b9f3891f3..8cc91f969 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java @@ -79,9 +79,9 @@ public class ServerCUIHandler { try { CuboidRegion region = ((CuboidRegionSelector) regionSelector).getRegion(); - posX = region.getMinimumPoint().getBlockX(); - posY = region.getMinimumPoint().getBlockY(); - posZ = region.getMinimumPoint().getBlockZ(); + posX = region.getMinimumPoint().x(); + posY = region.getMinimumPoint().y(); + posZ = region.getMinimumPoint().z(); width = region.getWidth(); height = region.getHeight(); @@ -104,9 +104,9 @@ public class ServerCUIHandler { } // Just select the point. - posX = point.getBlockX(); - posY = point.getBlockY(); - posZ = point.getBlockZ(); + posX = point.x(); + posY = point.y(); + posZ = point.z(); width = 1; height = 1; length = 1; @@ -128,8 +128,8 @@ public class ServerCUIHandler { double rotX = location.getYaw(); double rotY = location.getPitch(); double xz = Math.cos(Math.toRadians(rotY)); - int x = (int) (location.getX() - (-xz * Math.sin(Math.toRadians(rotX))) * 12); - int z = (int) (location.getZ() - (xz * Math.cos(Math.toRadians(rotX))) * 12); + int x = (int) (location.x() - (-xz * Math.sin(Math.toRadians(rotX))) * 12); + int z = (int) (location.z() - (xz * Math.cos(Math.toRadians(rotX))) * 12); int y = Math.max( player.getWorld().getMinY(), Math.min(Math.min(player.getWorld().getMaxY(), posY + MAX_DISTANCE), posY + 3) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/RegionOptimizedVectorSorter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/RegionOptimizedVectorSorter.java index b30bd8f49..4fdcb2118 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/RegionOptimizedVectorSorter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/RegionOptimizedVectorSorter.java @@ -62,13 +62,13 @@ public class RegionOptimizedVectorSorter { private static final long FLIP_REGION_Z_SIGN = 0x1_00_00L << REGION_Z_SHIFT; private static long key(BlockVector3 elem) { - long x = elem.getX(); - long z = elem.getZ(); + long x = elem.x(); + long z = elem.z(); return (((x << (REGION_X_SHIFT - 9)) & REGION_X_MASK) ^ FLIP_REGION_X_SIGN) | (((z << (REGION_Z_SHIFT - 9)) & REGION_Z_MASK) ^ FLIP_REGION_Z_SIGN) | ((x << (CHUNK_X_SHIFT - 4)) & CHUNK_X_MASK) | ((z << (CHUNK_Z_SHIFT - 4)) & CHUNK_Z_MASK) - | (Y_MAX - elem.getY()); + | (Y_MAX - elem.y()); } private static final int NUMBER_OF_BITS = 64; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java index 769773b96..aa90cb816 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java @@ -50,9 +50,9 @@ public interface WorldNativeAccess { checkNotNull(block); setCurrentSideEffectSet(sideEffects); - int x = position.getBlockX(); - int y = position.getBlockY(); - int z = position.getBlockZ(); + int x = position.x(); + int y = position.y(); + int z = position.z(); // First set the block NC chunk = getChunk(x >> 4, z >> 4); @@ -75,9 +75,9 @@ public interface WorldNativeAccess { if (tag != null) { tag = tag.put(ImmutableMap.of( "id", StringBinaryTag.of(baseBlock.getNbtId()), - "x", IntBinaryTag.of(position.getX()), - "y", IntBinaryTag.of(position.getY()), - "z", IntBinaryTag.of(position.getZ()) + "x", IntBinaryTag.of(position.x()), + "y", IntBinaryTag.of(position.y()), + "z", IntBinaryTag.of(position.z()) )); // update if TE changed as well @@ -99,8 +99,8 @@ public interface WorldNativeAccess { default void applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet) { setCurrentSideEffectSet(sideEffectSet); - NP pos = getPosition(position.getX(), position.getY(), position.getZ()); - NC chunk = getChunk(position.getX() >> 4, position.getZ() >> 4); + NP pos = getPosition(position.x(), position.y(), position.z()); + NC chunk = getChunk(position.x() >> 4, position.z() >> 4); NBS oldData = toNative(previousType); NBS newData = getBlockState(chunk, pos); 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 cb5784cce..baed5ffde 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 @@ -53,7 +53,7 @@ public class BlockVector2 { * */ public static final Comparator COMPARING_GRID_ARRANGEMENT = - Comparator.comparingInt(BlockVector2::getZ).thenComparingInt(BlockVector2::getX); + Comparator.comparingInt(BlockVector2::z).thenComparingInt(BlockVector2::x); public static BlockVector2 at(double x, double z) { return at((int) Math.floor(x), (int) Math.floor(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 e48355d63..3d239b352 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 @@ -254,7 +254,7 @@ public abstract class BlockVector3 { */ //FAWE start - getter public BlockVector3 withY(int y) { - return BlockVector3.at(getX(), y, getZ()); + return BlockVector3.at(x(), y, z()); } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/convolution/HeightMap.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/convolution/HeightMap.java index 68e62e937..0eeabee70 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/convolution/HeightMap.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/convolution/HeightMap.java @@ -89,10 +89,10 @@ public class HeightMap { this.maxSessionY = session.getMaxY(); //FAWE end - int minX = region.getMinimumPoint().getBlockX(); - int minY = region.getMinimumPoint().getBlockY(); - int minZ = region.getMinimumPoint().getBlockZ(); - int maxY = region.getMaximumPoint().getBlockY(); + int minX = region.getMinimumPoint().x(); + int minY = region.getMinimumPoint().y(); + int minZ = region.getMinimumPoint().z(); + int maxY = region.getMaximumPoint().y(); // Store current heightmap data data = new int[width * height]; @@ -100,14 +100,14 @@ public class HeightMap { //FAWE start if (layers) { BlockVector3 min = region.getMinimumPoint(); - int bx = min.getBlockX(); - int bz = min.getBlockZ(); + int bx = min.x(); + int bz = min.z(); Iterator flat = Regions.asFlatRegion(region).asFlatRegion().iterator(); int layer = session.getMinY(); while (flat.hasNext()) { BlockVector2 pos = flat.next(); - int x = pos.getBlockX(); - int z = pos.getBlockZ(); + int x = pos.x(); + int z = pos.z(); layer = session.getNearestSurfaceLayer(x, z, (layer + 7) >> 3, session.getMinY(), maxY); data[(z - bz) * width + (x - bx)] = layer; } @@ -169,10 +169,10 @@ public class HeightMap { checkNotNull(data); BlockVector3 min = region.getMinimumPoint(); - int originX = min.getBlockX(); - int originZ = min.getBlockZ(); + int originX = min.x(); + int originZ = min.z(); - int maxY = region.getMaximumPoint().getBlockY(); + int maxY = region.getMaximumPoint().y(); BlockState fillerAir = BlockTypes.AIR.getDefaultState(); @@ -261,11 +261,11 @@ public class HeightMap { checkNotNull(data); BlockVector3 min = region.getMinimumPoint(); - int originX = min.getBlockX(); - int originY = min.getBlockY(); - int originZ = min.getBlockZ(); + int originX = min.x(); + int originY = min.y(); + int originZ = min.z(); - int maxY = region.getMaximumPoint().getBlockY(); + int maxY = region.getMaximumPoint().y(); BlockState fillerAir = BlockTypes.AIR.getDefaultState(); int blocksChanged = 0; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/convolution/SnowHeightMap.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/convolution/SnowHeightMap.java index 97f58f9e1..0c12c4652 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/convolution/SnowHeightMap.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/convolution/SnowHeightMap.java @@ -65,10 +65,10 @@ public class SnowHeightMap { this.width = region.getWidth(); this.height = region.getLength(); - int minX = region.getMinimumPoint().getBlockX(); - int minY = region.getMinimumPoint().getBlockY(); - int minZ = region.getMinimumPoint().getBlockZ(); - int maxY = region.getMaximumPoint().getBlockY(); + int minX = region.getMinimumPoint().x(); + int minY = region.getMinimumPoint().y(); + int minZ = region.getMinimumPoint().z(); + int maxY = region.getMaximumPoint().y(); // Store current heightmap data data = new float[width * height]; @@ -134,11 +134,11 @@ public class SnowHeightMap { checkNotNull(data); BlockVector3 minY = region.getMinimumPoint(); - int originX = minY.getBlockX(); - int originY = minY.getBlockY(); - int originZ = minY.getBlockZ(); + int originX = minY.x(); + int originY = minY.y(); + int originZ = minY.z(); - int maxY = region.getMaximumPoint().getBlockY(); + int maxY = region.getMaximumPoint().y(); BlockState fillerAir = BlockTypes.AIR.getDefaultState(); BlockState fillerSnow = BlockTypes.SNOW_BLOCK.getDefaultState(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/interpolation/KochanekBartelsInterpolation.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/interpolation/KochanekBartelsInterpolation.java index 561ba14bf..0ecced12e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/interpolation/KochanekBartelsInterpolation.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/interpolation/KochanekBartelsInterpolation.java @@ -164,10 +164,10 @@ public class KochanekBartelsInterpolation implements Interpolation { //FAWE start double r2 = remainder * remainder; double r3 = r2 * remainder; - mutable.mutX((a.getX() * r3 + b.getX() * r2 + c.getX() * remainder + d.getX())); - mutable.mutY((a.getY() * r3 + b.getY() * r2 + c.getY() * remainder + d.getY())); - mutable.mutZ((a.getZ() * r3 + b.getZ() * r2 + c.getZ() * remainder + d.getZ())); - return Vector3.at(mutable.getX(), mutable.getY(), mutable.getZ()); + mutable.mutX((a.x() * r3 + b.x() * r2 + c.x() * remainder + d.x())); + mutable.mutY((a.y() * r3 + b.y() * r2 + c.y() * remainder + d.y())); + mutable.mutZ((a.z() * r3 + b.z() * r2 + c.z() * remainder + d.z())); + return Vector3.at(mutable.x(), mutable.y(), mutable.z()); //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/noise/JLibNoiseGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/noise/JLibNoiseGenerator.java index a7f3fe449..c541d2d3d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/noise/JLibNoiseGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/noise/JLibNoiseGenerator.java @@ -47,12 +47,12 @@ abstract class JLibNoiseGenerator implements NoiseGenerator { @Override public float noise(Vector2 position) { - return forceRange(module.GetValue(position.getX(), 0, position.getZ())); + return forceRange(module.GetValue(position.x(), 0, position.z())); } @Override public float noise(Vector3 position) { - return forceRange(module.GetValue(position.getX(), position.getY(), position.getZ())); + return forceRange(module.GetValue(position.x(), position.y(), position.z())); } private float forceRange(double value) { 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 02ee75d44..92e81eea2 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 @@ -265,11 +265,11 @@ public class AffineTransform implements Transform, Serializable { } public AffineTransform translate(Vector3 vec) { - return translate(vec.getX(), vec.getY(), vec.getZ()); + return translate(vec.x(), vec.y(), vec.z()); } public AffineTransform translate(BlockVector3 vec) { - return translate(vec.getX(), vec.getY(), vec.getZ()); + return translate(vec.x(), vec.y(), vec.z()); } public AffineTransform translate(double x, double y, double z) { @@ -315,29 +315,29 @@ public class AffineTransform implements Transform, Serializable { } public AffineTransform scale(Vector3 vec) { - return scale(vec.getX(), vec.getY(), vec.getZ()); + return scale(vec.x(), vec.y(), vec.z()); } //FAWE start public boolean isScaled(Vector3 vector) { - boolean flip = vector.getX() != 0 && m00 < 0; - if (vector.getY() != 0 && m11 < 0) { + boolean flip = vector.x() != 0 && m00 < 0; + if (vector.y() != 0 && m11 < 0) { flip = !flip; } - if (vector.getZ() != 0 && m22 < 0) { + if (vector.z() != 0 && m22 < 0) { flip = !flip; } if (flip) { return true; } // Check for flip-and-rotate - if (vector.getX() != 0 && vector.getY() != 0 && ((m01 < 0 && m10 < 0) || (m01 > 0 && m10 > 0))) { + if (vector.x() != 0 && vector.y() != 0 && ((m01 < 0 && m10 < 0) || (m01 > 0 && m10 > 0))) { flip = true; } - if (vector.getX() != 0 && vector.getZ() != 0 && ((m02 < 0 && m20 < 0) || (m02 > 0 && m20 > 0))) { + if (vector.x() != 0 && vector.z() != 0 && ((m02 < 0 && m20 < 0) || (m02 > 0 && m20 > 0))) { flip = !flip; } - if (vector.getY() != 0 && vector.getZ() != 0 && ((m12 < 0 && m21 < 0) || (m12 > 0 && m21 > 0))) { + if (vector.y() != 0 && vector.z() != 0 && ((m12 < 0 && m21 < 0) || (m12 > 0 && m21 > 0))) { flip = !flip; } return flip; @@ -346,9 +346,9 @@ public class AffineTransform implements Transform, Serializable { @Override public Vector3 apply(Vector3 vector) { - double x = (vector.getX() * m00 + vector.getY() * m01 + vector.getZ() * m02 + m03); - double y = (vector.getX() * m10 + vector.getY() * m11 + vector.getZ() * m12 + m13); - double z = (vector.getX() * m20 + vector.getY() * m21 + vector.getZ() * m22 + m23); + double x = (vector.x() * m00 + vector.y() * m01 + vector.z() * m02 + m03); + double y = (vector.x() * m10 + vector.y() * m11 + vector.z() * m12 + m13); + double z = (vector.x() * m20 + vector.y() * m21 + vector.z() * m22 + m23); vector = vector.mutX(x); vector = vector.mutY(y); vector = vector.mutZ(z); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractFlatRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractFlatRegion.java index 8534f0f35..a868e0262 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractFlatRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractFlatRegion.java @@ -29,12 +29,12 @@ public abstract class AbstractFlatRegion extends AbstractRegion implements FlatR @Override public int getMinimumY() { - return getMinimumPoint().getBlockY(); + return getMinimumPoint().y(); } @Override public int getMaximumY() { - return getMaximumPoint().getBlockY(); + return getMaximumPoint().y(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java index 85979b217..f87f9741b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java @@ -20,8 +20,6 @@ package com.sk89q.worldedit.regions; import com.fastasyncworldedit.core.math.BlockVectorSet; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; @@ -109,10 +107,10 @@ public abstract class AbstractRegion extends AbstractSet implement final List points = new ArrayList<>(4); - points.add(BlockVector2.at(min.getX(), min.getZ())); - points.add(BlockVector2.at(min.getX(), max.getZ())); - points.add(BlockVector2.at(max.getX(), max.getZ())); - points.add(BlockVector2.at(max.getX(), min.getZ())); + points.add(BlockVector2.at(min.x(), min.z())); + points.add(BlockVector2.at(min.x(), max.z())); + points.add(BlockVector2.at(max.x(), max.z())); + points.add(BlockVector2.at(max.x(), min.z())); return points; } @@ -122,9 +120,9 @@ public abstract class AbstractRegion extends AbstractSet implement BlockVector3 min = getMinimumPoint(); BlockVector3 max = getMaximumPoint(); - return (max.getX() - min.getX() + 1L) - * (max.getY() - min.getY() + 1L) - * (max.getZ() - min.getZ() + 1L); + return (max.x() - min.x() + 1L) + * (max.y() - min.y() + 1L) + * (max.z() - min.z() + 1L); } /** @@ -137,7 +135,7 @@ public abstract class AbstractRegion extends AbstractSet implement BlockVector3 min = getMinimumPoint(); BlockVector3 max = getMaximumPoint(); - return max.getX() - min.getX() + 1; + return max.x() - min.x() + 1; } /** @@ -150,7 +148,7 @@ public abstract class AbstractRegion extends AbstractSet implement BlockVector3 min = getMinimumPoint(); BlockVector3 max = getMaximumPoint(); - return max.getY() - min.getY() + 1; + return max.y() - min.y() + 1; } /** @@ -163,7 +161,7 @@ public abstract class AbstractRegion extends AbstractSet implement BlockVector3 min = getMinimumPoint(); BlockVector3 max = getMaximumPoint(); - return max.getZ() - min.getZ() + 1; + return max.z() - min.z() + 1; } /** @@ -179,12 +177,12 @@ public abstract class AbstractRegion extends AbstractSet implement final BlockVector3 maxBlock = getMaximumPoint(); //FAWE start - final BlockVector2 min = BlockVector2.at(minBlock.getX() >> 4, minBlock.getZ() >> 4); - final BlockVector2 max = BlockVector2.at(maxBlock.getX() >> 4, maxBlock.getZ() >> 4); + final BlockVector2 min = BlockVector2.at(minBlock.x() >> 4, minBlock.z() >> 4); + final BlockVector2 max = BlockVector2.at(maxBlock.x() >> 4, maxBlock.z() >> 4); //FAWE end - for (int X = min.getBlockX(); X <= max.getBlockX(); ++X) { - for (int Z = min.getBlockZ(); Z <= max.getBlockZ(); ++Z) { + for (int X = min.x(); X <= max.x(); ++X) { + for (int Z = min.z(); Z <= max.z(); ++Z) { if (containsChunk(X, Z)) { chunks.add(BlockVector2.at(X, Z)); } @@ -201,9 +199,9 @@ public abstract class AbstractRegion extends AbstractSet implement final BlockVector3 min = getMinimumPoint(); final BlockVector3 max = getMaximumPoint(); - for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) { - for (int y = min.getBlockY(); y <= max.getBlockY(); ++y) { - for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) { + for (int x = min.x(); x <= max.x(); ++x) { + for (int y = min.y(); y <= max.y(); ++y) { + for (int z = min.z(); z <= max.z(); ++z) { if (!contains(BlockVector3.at(x, y, z))) { continue; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index d04e5aa8c..8616cbb2b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -160,12 +160,12 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { } pos1 = pos1.clampY(getWorldMinY(), getWorldMaxY()); pos2 = pos2.clampY(getWorldMinY(), getWorldMaxY()); - minX = Math.min(pos1.getX(), pos2.getX()); - minY = Math.min(pos1.getY(), pos2.getY()); - minZ = Math.min(pos1.getZ(), pos2.getZ()); - maxX = Math.max(pos1.getX(), pos2.getX()); - maxY = Math.max(pos1.getY(), pos2.getY()); - maxZ = Math.max(pos1.getZ(), pos2.getZ()); + minX = Math.min(pos1.x(), pos2.x()); + minY = Math.min(pos1.y(), pos2.y()); + minZ = Math.min(pos1.z(), pos2.z()); + maxX = Math.max(pos1.x(), pos2.x()); + maxY = Math.max(pos1.y(), pos2.y()); + maxZ = Math.max(pos1.z(), pos2.z()); } //FAWE start - allow region to be created without clamping Y @@ -176,12 +176,12 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { if (pos1 == null || pos2 == null) { return; } - minX = Math.min(pos1.getX(), pos2.getX()); - minY = Math.min(pos1.getY(), pos2.getY()); - minZ = Math.min(pos1.getZ(), pos2.getZ()); - maxX = Math.max(pos1.getX(), pos2.getX()); - maxY = Math.max(pos1.getY(), pos2.getY()); - maxZ = Math.max(pos1.getZ(), pos2.getZ()); + minX = Math.min(pos1.x(), pos2.x()); + minY = Math.min(pos1.y(), pos2.y()); + minZ = Math.min(pos1.z(), pos2.z()); + maxX = Math.max(pos1.x(), pos2.x()); + maxY = Math.max(pos1.y(), pos2.y()); + maxZ = Math.max(pos1.z(), pos2.z()); } //FAWE end @@ -196,16 +196,16 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return new RegionIntersection( // Project to Z-Y plane - new CuboidRegion(pos1.withX(min.getX()), pos2.withX(min.getX())), - new CuboidRegion(pos1.withX(max.getX()), pos2.withX(max.getX())), + new CuboidRegion(pos1.withX(min.x()), pos2.withX(min.x())), + new CuboidRegion(pos1.withX(max.x()), pos2.withX(max.x())), // Project to X-Y plane - new CuboidRegion(pos1.withZ(min.getZ()), pos2.withZ(min.getZ())), - new CuboidRegion(pos1.withZ(max.getZ()), pos2.withZ(max.getZ())), + new CuboidRegion(pos1.withZ(min.z()), pos2.withZ(min.z())), + new CuboidRegion(pos1.withZ(max.z()), pos2.withZ(max.z())), // Project to the X-Z plane - new CuboidRegion(pos1.withY(min.getY()), pos2.withY(min.getY())), - new CuboidRegion(pos1.withY(max.getY()), pos2.withY(max.getY())) + new CuboidRegion(pos1.withY(min.y()), pos2.withY(min.y())), + new CuboidRegion(pos1.withY(max.y()), pos2.withY(max.y())) ); } @@ -221,7 +221,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { BlockVector3 dimensions = getDimensions(); //FAWE start - if (dimensions.getX() <= 2 || dimensions.getZ() <= 2) { + if (dimensions.x() <= 2 || dimensions.z() <= 2) { // The wall are the region return new RegionIntersection(this); } @@ -229,18 +229,18 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return new RegionIntersection( // Project to Z-Y plane - new CuboidRegion(pos1.withX(min.getX()), pos2.withX(min.getX())), - new CuboidRegion(pos1.withX(max.getX()), pos2.withX(max.getX())), + new CuboidRegion(pos1.withX(min.x()), pos2.withX(min.x())), + new CuboidRegion(pos1.withX(max.x()), pos2.withX(max.x())), // Project to X-Y plane //FAWE start = prevent overlap new CuboidRegion( - pos1.withZ(min.getZ()).add(BlockVector3.UNIT_X), - pos2.withZ(min.getZ()).subtract(BlockVector3.UNIT_X) + pos1.withZ(min.z()).add(BlockVector3.UNIT_X), + pos2.withZ(min.z()).subtract(BlockVector3.UNIT_X) ), new CuboidRegion( - pos1.withZ(max.getZ()).add(BlockVector3.UNIT_X), - pos2.withZ(max.getZ()).subtract(BlockVector3.UNIT_X) + pos1.withZ(max.z()).add(BlockVector3.UNIT_X), + pos2.withZ(max.z()).subtract(BlockVector3.UNIT_X) ) //FAWE end ); @@ -276,45 +276,45 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { checkNotNull(changes); for (BlockVector3 change : changes) { - if (change.getX() > 0) { - if (Math.max(pos1.getX(), pos2.getX()) == pos1.getX()) { - pos1 = pos1.add(change.getX(), 0, 0); + if (change.x() > 0) { + if (Math.max(pos1.x(), pos2.x()) == pos1.x()) { + pos1 = pos1.add(change.x(), 0, 0); } else { - pos2 = pos2.add(change.getX(), 0, 0); + pos2 = pos2.add(change.x(), 0, 0); } } else { - if (Math.min(pos1.getX(), pos2.getX()) == pos1.getX()) { - pos1 = pos1.add(change.getX(), 0, 0); + if (Math.min(pos1.x(), pos2.x()) == pos1.x()) { + pos1 = pos1.add(change.x(), 0, 0); } else { - pos2 = pos2.add(change.getX(), 0, 0); + pos2 = pos2.add(change.x(), 0, 0); } } - if (change.getY() > 0) { - if (Math.max(pos1.getY(), pos2.getY()) == pos1.getY()) { - pos1 = pos1.add(0, change.getY(), 0); + if (change.y() > 0) { + if (Math.max(pos1.y(), pos2.y()) == pos1.y()) { + pos1 = pos1.add(0, change.y(), 0); } else { - pos2 = pos2.add(0, change.getY(), 0); + pos2 = pos2.add(0, change.y(), 0); } } else { - if (Math.min(pos1.getY(), pos2.getY()) == pos1.getY()) { - pos1 = pos1.add(0, change.getY(), 0); + if (Math.min(pos1.y(), pos2.y()) == pos1.y()) { + pos1 = pos1.add(0, change.y(), 0); } else { - pos2 = pos2.add(0, change.getY(), 0); + pos2 = pos2.add(0, change.y(), 0); } } - if (change.getZ() > 0) { - if (Math.max(pos1.getZ(), pos2.getZ()) == pos1.getZ()) { - pos1 = pos1.add(0, 0, change.getZ()); + if (change.z() > 0) { + if (Math.max(pos1.z(), pos2.z()) == pos1.z()) { + pos1 = pos1.add(0, 0, change.z()); } else { - pos2 = pos2.add(0, 0, change.getZ()); + pos2 = pos2.add(0, 0, change.z()); } } else { - if (Math.min(pos1.getZ(), pos2.getZ()) == pos1.getZ()) { - pos1 = pos1.add(0, 0, change.getZ()); + if (Math.min(pos1.z(), pos2.z()) == pos1.z()) { + pos1 = pos1.add(0, 0, change.z()); } else { - pos2 = pos2.add(0, 0, change.getZ()); + pos2 = pos2.add(0, 0, change.z()); } } } @@ -327,45 +327,45 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { checkNotNull(changes); for (BlockVector3 change : changes) { - if (change.getX() < 0) { - if (Math.max(pos1.getX(), pos2.getX()) == pos1.getX()) { - pos1 = pos1.add(change.getX(), 0, 0); + if (change.x() < 0) { + if (Math.max(pos1.x(), pos2.x()) == pos1.x()) { + pos1 = pos1.add(change.x(), 0, 0); } else { - pos2 = pos2.add(change.getX(), 0, 0); + pos2 = pos2.add(change.x(), 0, 0); } } else { - if (Math.min(pos1.getX(), pos2.getX()) == pos1.getX()) { - pos1 = pos1.add(change.getX(), 0, 0); + if (Math.min(pos1.x(), pos2.x()) == pos1.x()) { + pos1 = pos1.add(change.x(), 0, 0); } else { - pos2 = pos2.add(change.getX(), 0, 0); + pos2 = pos2.add(change.x(), 0, 0); } } - if (change.getY() < 0) { - if (Math.max(pos1.getY(), pos2.getY()) == pos1.getY()) { - pos1 = pos1.add(0, change.getY(), 0); + if (change.y() < 0) { + if (Math.max(pos1.y(), pos2.y()) == pos1.y()) { + pos1 = pos1.add(0, change.y(), 0); } else { - pos2 = pos2.add(0, change.getY(), 0); + pos2 = pos2.add(0, change.y(), 0); } } else { - if (Math.min(pos1.getY(), pos2.getY()) == pos1.getY()) { - pos1 = pos1.add(0, change.getY(), 0); + if (Math.min(pos1.y(), pos2.y()) == pos1.y()) { + pos1 = pos1.add(0, change.y(), 0); } else { - pos2 = pos2.add(0, change.getY(), 0); + pos2 = pos2.add(0, change.y(), 0); } } - if (change.getZ() < 0) { - if (Math.max(pos1.getZ(), pos2.getZ()) == pos1.getZ()) { - pos1 = pos1.add(0, 0, change.getZ()); + if (change.z() < 0) { + if (Math.max(pos1.z(), pos2.z()) == pos1.z()) { + pos1 = pos1.add(0, 0, change.z()); } else { - pos2 = pos2.add(0, 0, change.getZ()); + pos2 = pos2.add(0, 0, change.z()); } } else { - if (Math.min(pos1.getZ(), pos2.getZ()) == pos1.getZ()) { - pos1 = pos1.add(0, 0, change.getZ()); + if (Math.min(pos1.z(), pos2.z()) == pos1.z()) { + pos1 = pos1.add(0, 0, change.z()); } else { - pos2 = pos2.add(0, 0, change.getZ()); + pos2 = pos2.add(0, 0, change.z()); } } } @@ -385,10 +385,10 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { public Set getChunks() { BlockVector3 min = getMinimumPoint(); BlockVector3 max = getMaximumPoint(); - final int maxX = max.getBlockX() >> ChunkStore.CHUNK_SHIFTS; - final int minX = min.getBlockX() >> ChunkStore.CHUNK_SHIFTS; - final int maxZ = max.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; - final int minZ = min.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; + final int maxX = max.x() >> ChunkStore.CHUNK_SHIFTS; + final int minX = min.x() >> ChunkStore.CHUNK_SHIFTS; + final int maxZ = max.z() >> ChunkStore.CHUNK_SHIFTS; + final int minZ = min.z() >> ChunkStore.CHUNK_SHIFTS; final int size = (maxX - minX + 1) * (maxZ - minZ + 1); //FAWE start @@ -471,7 +471,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { public boolean contains(Object o) { if (o instanceof BlockVector2) { BlockVector2 cv = (BlockVector2) o; - return cv.getX() >= minX && cv.getX() <= maxX && cv.getZ() >= minZ && cv.getZ() <= maxZ; + return cv.x() >= minX && cv.x() <= maxX && cv.z() >= minZ && cv.z() <= maxZ; } return false; } @@ -488,9 +488,9 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { BlockVector3 min = getMinimumPoint(); BlockVector3 max = getMaximumPoint(); - for (int x = min.getBlockX() >> ChunkStore.CHUNK_SHIFTS; x <= max.getBlockX() >> ChunkStore.CHUNK_SHIFTS; ++x) { - for (int z = min.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; z <= max.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; ++z) { - for (int y = min.getBlockY() >> ChunkStore.CHUNK_SHIFTS; y <= max.getBlockY() >> ChunkStore.CHUNK_SHIFTS; ++y) { + for (int x = min.x() >> ChunkStore.CHUNK_SHIFTS; x <= max.x() >> ChunkStore.CHUNK_SHIFTS; ++x) { + for (int z = min.z() >> ChunkStore.CHUNK_SHIFTS; z <= max.z() >> ChunkStore.CHUNK_SHIFTS; ++z) { + for (int y = min.y() >> ChunkStore.CHUNK_SHIFTS; y <= max.y() >> ChunkStore.CHUNK_SHIFTS; ++y) { chunks.add(BlockVector3.at(x, y, z)); } } @@ -503,7 +503,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { @Override public boolean contains(BlockVector3 position) { //FAWE start - return contains(position.getX(), position.getY(), position.getZ()); + return contains(position.x(), position.y(), position.z()); //FAWE end } @@ -532,17 +532,17 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { private final BlockVector3 min = getMinimumPoint(); private final BlockVector3 max = getMaximumPoint(); - final int bx = min.getBlockX(); - final int by = min.getBlockY(); - final int bz = min.getBlockZ(); + final int bx = min.x(); + final int by = min.y(); + final int bz = min.z(); - final int tx = max.getBlockX(); - final int ty = max.getBlockY(); - final int tz = max.getBlockZ(); + final int tx = max.x(); + final int ty = max.y(); + final int tz = max.z(); - private int x = min.getBlockX(); - private int y = min.getBlockY(); - private int z = min.getBlockZ(); + private int x = min.x(); + private int y = min.y(); + private int z = min.z(); int cx = x >> 4; int cz = z >> 4; @@ -611,9 +611,9 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return new Iterator() { private final BlockVector3 min = getMinimumPoint(); private final BlockVector3 max = getMaximumPoint(); - private int nextX = min.getBlockX(); - private int nextY = min.getBlockY(); - private int nextZ = min.getBlockZ(); + private int nextX = min.x(); + private int nextY = min.y(); + private int nextZ = min.z(); private boolean hasNext = true; @Override @@ -626,17 +626,17 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { mutable.mutX(nextX); mutable.mutY(nextY); mutable.mutZ(nextZ); - if (++nextX > max.getBlockX()) { - nextX = min.getBlockX(); - if (++nextZ > max.getBlockZ()) { - nextZ = min.getBlockZ(); - if (++nextY > max.getBlockY()) { + if (++nextX > max.x()) { + nextX = min.x(); + if (++nextZ > max.z()) { + nextZ = min.z(); + if (++nextY > max.y()) { if (!hasNext()) { throw new NoSuchElementException(); } - nextX = max.getBlockX(); - nextZ = max.getBlockZ(); - nextY = max.getBlockY(); + nextX = max.x(); + nextZ = max.z(); + nextY = max.y(); hasNext = false; } } @@ -652,8 +652,8 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return () -> new Iterator() { private final BlockVector3 min = getMinimumPoint(); private final BlockVector3 max = getMaximumPoint(); - private int nextX = min.getBlockX(); - private int nextZ = min.getBlockZ(); + private int nextX = min.x(); + private int nextZ = min.z(); @Override public boolean hasNext() { @@ -666,9 +666,9 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { throw new NoSuchElementException(); } BlockVector2 answer = BlockVector2.at(nextX, nextZ); - if (++nextX > max.getBlockX()) { - nextX = min.getBlockX(); - if (++nextZ > max.getBlockZ()) { + if (++nextX > max.x()) { + nextX = min.x(); + if (++nextZ > max.z()) { nextZ = Integer.MAX_VALUE; nextX = Integer.MAX_VALUE; } @@ -705,10 +705,10 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { public static boolean contains(CuboidRegion region) { BlockVector3 min = region.getMinimumPoint(); BlockVector3 max = region.getMaximumPoint(); - return region.contains(min.getBlockX(), min.getBlockY(), min.getBlockZ()) && region.contains( - max.getBlockX(), - max.getBlockY(), - max.getBlockZ() + return region.contains(min.x(), min.y(), min.z()) && region.contains( + max.x(), + max.y(), + max.z() ); } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java index 6439d6079..85c62e771 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java @@ -197,8 +197,8 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { @Override public long getVolume() { - return BigDecimal.valueOf(radius.getX()) - .multiply(BigDecimal.valueOf(radius.getZ())) + return BigDecimal.valueOf(radius.x()) + .multiply(BigDecimal.valueOf(radius.z())) .multiply(PI) .multiply(BigDecimal.valueOf(getHeight())) .setScale(0, RoundingMode.FLOOR) @@ -207,7 +207,7 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { @Override public int getWidth() { - return (int) (2 * radius.getX()); + return (int) (2 * radius.x()); } @Override @@ -217,7 +217,7 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { @Override public int getLength() { - return (int) (2 * radius.getZ()); + return (int) (2 * radius.z()); } private BlockVector2 calculateDiff2D(BlockVector3... changes) throws RegionOperationException { @@ -226,7 +226,7 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { diff = diff.add(change.toBlockVector2()); } - if ((diff.getBlockX() & 1) + (diff.getBlockZ() & 1) != 0) { + if ((diff.x() & 1) + (diff.z() & 1) != 0) { throw new RegionOperationException(Caption.of("worldedit.selection.cylinder.error.even-horizontal")); } @@ -254,7 +254,7 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { radius = radius.add(calculateChanges2D(changes).toVector2()); this.radiusInverse = Vector2.ONE.divide(radius); for (BlockVector3 change : changes) { - int changeY = change.getBlockY(); + int changeY = change.y(); if (changeY > 0) { maxY += changeY; } else { @@ -276,7 +276,7 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { this.radiusInverse = Vector2.ONE.divide(radius); for (BlockVector3 change : changes) { int height = maxY - minY; - int changeY = change.getBlockY(); + int changeY = change.y(); if (changeY > 0) { minY += Math.min(height, changeY); } else { @@ -289,7 +289,7 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { public void shift(BlockVector3 change) throws RegionOperationException { center = center.add(change.toBlockVector2()); - int changeY = change.getBlockY(); + int changeY = change.y(); maxY += changeY; minY += changeY; } @@ -322,15 +322,15 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { @Override public boolean contains(int x, int z) { - double dx = Math.abs(x - center.getBlockX()) * radiusInverse.getX(); - double dz = Math.abs(z - center.getBlockZ()) * radiusInverse.getZ(); + double dx = Math.abs(x - center.x()) * radiusInverse.x(); + double dz = Math.abs(z - center.z()) * radiusInverse.z(); return dx * dx + dz * dz <= 1; } @Override public boolean contains(BlockVector3 position) { - return contains(position.getX(), position.getY(), position.getZ()); + return contains(position.x(), position.y(), position.z()); } //FAWE end @@ -402,8 +402,8 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { checkNotNull(extent); checkNotNull(center); Vector2 radiusVec = Vector2.at(radius, radius); - int minY = extent.getMinimumPoint().getBlockY(); - int maxY = extent.getMaximumPoint().getBlockY(); + int minY = extent.getMinimumPoint().y(); + int maxY = extent.getMaximumPoint().y(); return new CylinderRegion(center, radiusVec, minY, maxY); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java index c3aed2a53..944e7a14c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java @@ -102,32 +102,32 @@ public class EllipsoidRegion extends AbstractRegion { @Override public long getVolume() { return ELLIPSOID_BASE_MULTIPLIER - .multiply(BigDecimal.valueOf(radius.getX())) - .multiply(BigDecimal.valueOf(radius.getY())) - .multiply(BigDecimal.valueOf(radius.getZ())) + .multiply(BigDecimal.valueOf(radius.x())) + .multiply(BigDecimal.valueOf(radius.y())) + .multiply(BigDecimal.valueOf(radius.z())) .setScale(0, RoundingMode.FLOOR) .longValue(); } @Override public int getWidth() { - return (int) (2 * radius.getX()); + return (int) (2 * radius.x()); } @Override public int getHeight() { - return (int) (2 * radius.getY()); + return (int) (2 * radius.y()); } @Override public int getLength() { - return (int) (2 * radius.getZ()); + return (int) (2 * radius.z()); } private BlockVector3 calculateDiff(BlockVector3... changes) throws RegionOperationException { BlockVector3 diff = BlockVector3.ZERO.add(changes); - if ((diff.getBlockX() & 1) + (diff.getBlockY() & 1) + (diff.getBlockZ() & 1) != 0) { + if ((diff.x() & 1) + (diff.y() & 1) + (diff.z() & 1) != 0) { throw new RegionOperationException(Caption.of("worldedit.selection.ellipsoid.error.even-horizontal")); } @@ -198,8 +198,8 @@ public class EllipsoidRegion extends AbstractRegion { this.radius = radius.add(0.5, 0.5, 0.5); //FAWE start radiusSqr = radius.multiply(radius); - radiusLengthSqr = (int) radiusSqr.getX(); - this.sphere = radius.getY() == radius.getX() && radius.getX() == radius.getZ(); + radiusLengthSqr = (int) radiusSqr.x(); + this.sphere = radius.y() == radius.x() && radius.x() == radius.z(); inverseRadiusSqr = Vector3.ONE.divide(radiusSqr); //FAWE end } @@ -210,10 +210,10 @@ public class EllipsoidRegion extends AbstractRegion { final BlockVector3 min = getMinimumPoint(); final BlockVector3 max = getMaximumPoint(); - final int centerY = center.getBlockY(); + final int centerY = center.y(); - for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) { - for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) { + for (int x = min.x(); x <= max.x(); ++x) { + for (int z = min.z(); z <= max.z(); ++z) { if (!contains(x, centerY, z)) { continue; } @@ -231,17 +231,17 @@ public class EllipsoidRegion extends AbstractRegion { //FAWE start @Override public boolean contains(int x, int y, int z) { - int cx = x - center.getBlockX(); + int cx = x - center.x(); int cx2 = cx * cx; if (cx2 > radiusSqr.getBlockX()) { return false; } - int cz = z - center.getBlockZ(); + int cz = z - center.z(); int cz2 = cz * cz; if (cz2 > radiusSqr.getBlockZ()) { return false; } - int cy = y - center.getBlockY(); + int cy = y - center.y(); int cy2 = cy * cy; if (radiusSqr.getBlockY() < getWorldMaxY() && cy2 > radiusSqr.getBlockY()) { return false; @@ -249,9 +249,9 @@ public class EllipsoidRegion extends AbstractRegion { if (sphere) { return cx2 + cy2 + cz2 <= radiusLengthSqr; } - double cxd = cx2 * inverseRadiusSqr.getX(); - double cyd = cy2 * inverseRadiusSqr.getY(); - double czd = cz2 * inverseRadiusSqr.getZ(); + double cxd = cx2 * inverseRadiusSqr.x(); + double cyd = cy2 * inverseRadiusSqr.y(); + double czd = cz2 * inverseRadiusSqr.z(); return cxd + cyd + czd <= 1; } @@ -265,23 +265,23 @@ public class EllipsoidRegion extends AbstractRegion { @Override public boolean contains(BlockVector3 position) { - return contains(position.getX(), position.getY(), position.getZ()); + return contains(position.x(), position.y(), position.z()); } @Override public boolean contains(int x, int z) { - int cx = x - center.getBlockX(); + int cx = x - center.x(); int cx2 = cx * cx; if (cx2 > radiusSqr.getBlockX()) { return false; } - int cz = z - center.getBlockZ(); + int cz = z - center.z(); int cz2 = cz * cz; if (cz2 > radiusSqr.getBlockZ()) { return false; } - double cxd = cx2 * inverseRadiusSqr.getX(); - double czd = cz2 * inverseRadiusSqr.getZ(); + double cxd = cx2 * inverseRadiusSqr.x(); + double czd = cz2 * inverseRadiusSqr.z(); return cxd + czd <= 1; } //FAWE end @@ -339,9 +339,9 @@ public class EllipsoidRegion extends AbstractRegion { int layer, int y1, int y2, int bx, int bz, Filter filter, ChunkFilterBlock block, IChunkGet get, IChunkSet set ) { - int cx = center.getBlockX(); - int cy = center.getBlockY(); - int cz = center.getBlockZ(); + int cx = center.x(); + int cy = center.y(); + int cz = center.z(); block.initLayer(get, set, layer); @@ -376,8 +376,8 @@ public class EllipsoidRegion extends AbstractRegion { ) { // Check bounds // This needs to be able to perform 50M blocks/sec otherwise it becomes a bottleneck - int cx = center.getBlockX(); - int cz = center.getBlockZ(); + int cx = center.x(); + int cz = center.z(); int bx = chunk.getX() << 4; int bz = chunk.getZ() << 4; int tx = bx + 15; @@ -415,7 +415,7 @@ public class EllipsoidRegion extends AbstractRegion { block = block.initChunk(chunk.getX(), chunk.getZ()); // Get the solid layers - int cy = center.getBlockY(); + int cy = center.y(); int diffYFull = MathMan.usqrt(diffY2); int yBotFull = Math.max(getWorldMinY(), cy - diffYFull); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegion.java index 021e042be..b07503762 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Polygonal2DRegion.java @@ -111,14 +111,14 @@ public class Polygonal2DRegion extends AbstractRegion implements FlatRegion { return; } - int minX = points.get(0).getBlockX(); - int minZ = points.get(0).getBlockZ(); - int maxX = points.get(0).getBlockX(); - int maxZ = points.get(0).getBlockZ(); + int minX = points.get(0).x(); + int minZ = points.get(0).z(); + int maxX = points.get(0).x(); + int maxZ = points.get(0).z(); for (BlockVector2 v : points) { - int x = v.getBlockX(); - int z = v.getBlockZ(); + int x = v.x(); + int z = v.z(); if (x < minX) { minX = x; } @@ -161,7 +161,7 @@ public class Polygonal2DRegion extends AbstractRegion implements FlatRegion { * @param position the position */ public void addPoint(BlockVector3 position) { - points.add(BlockVector2.at(position.getBlockX(), position.getBlockZ())); + points.add(BlockVector2.at(position.x(), position.z())); recalculate(); } @@ -214,8 +214,8 @@ public class Polygonal2DRegion extends AbstractRegion implements FlatRegion { int j = points.size() - 1; for (i = 0; i < points.size(); ++i) { - long x = points.get(j).getBlockX() + points.get(i).getBlockX(); - long z = points.get(j).getBlockZ() - points.get(i).getBlockZ(); + long x = points.get(j).x() + points.get(i).x(); + long z = points.get(j).z() - points.get(i).z(); area += x * z; j = i; } @@ -229,7 +229,7 @@ public class Polygonal2DRegion extends AbstractRegion implements FlatRegion { @Override public int getWidth() { - return max.getBlockX() - min.getBlockX() + 1; + return max.x() - min.x() + 1; } @Override @@ -239,16 +239,16 @@ public class Polygonal2DRegion extends AbstractRegion implements FlatRegion { @Override public int getLength() { - return max.getBlockZ() - min.getBlockZ() + 1; + return max.z() - min.z() + 1; } @Override public void expand(BlockVector3... changes) throws RegionOperationException { for (BlockVector3 change : changes) { - if (change.getBlockX() != 0 || change.getBlockZ() != 0) { + if (change.x() != 0 || change.z() != 0) { throw new RegionOperationException(Caption.of("worldedit.selection.polygon2d.error.expand-only-vertical")); } - int changeY = change.getBlockY(); + int changeY = change.y(); if (changeY > 0) { maxY += changeY; } else { @@ -261,10 +261,10 @@ public class Polygonal2DRegion extends AbstractRegion implements FlatRegion { @Override public void contract(BlockVector3... changes) throws RegionOperationException { for (BlockVector3 change : changes) { - if (change.getBlockX() != 0 || change.getBlockZ() != 0) { + if (change.x() != 0 || change.z() != 0) { throw new RegionOperationException(Caption.of("worldedit.selection.polygon2d.error.contract-only-vertical")); } - int changeY = change.getBlockY(); + int changeY = change.y(); if (changeY > 0) { minY += changeY; } else { @@ -276,13 +276,13 @@ public class Polygonal2DRegion extends AbstractRegion implements FlatRegion { @Override public void shift(BlockVector3 change) throws RegionOperationException { - final double changeX = change.getX(); - final double changeY = change.getY(); - final double changeZ = change.getZ(); + final double changeX = change.x(); + final double changeY = change.y(); + final double changeZ = change.z(); for (int i = 0; i < points.size(); ++i) { BlockVector2 point = points.get(i); - points.set(i, BlockVector2.at(point.getX() + changeX, point.getZ() + changeZ)); + points.set(i, BlockVector2.at(point.x() + changeX, point.z() + changeZ)); } minY += changeY; @@ -307,12 +307,12 @@ public class Polygonal2DRegion extends AbstractRegion implements FlatRegion { long crossproduct; int i; - xOld = points.get(npoints - 1).getBlockX(); - zOld = points.get(npoints - 1).getBlockZ(); + xOld = points.get(npoints - 1).x(); + zOld = points.get(npoints - 1).z(); for (i = 0; i < npoints; ++i) { - xNew = points.get(i).getBlockX(); - zNew = points.get(i).getBlockZ(); + xNew = points.get(i).x(); + zNew = points.get(i).z(); //Check for corner if (xNew == targetX && zNew == targetZ) { return true; @@ -365,9 +365,9 @@ public class Polygonal2DRegion extends AbstractRegion implements FlatRegion { if (points.size() < 3) { return false; } - int targetX = pt.getBlockX(); //wide - int targetY = pt.getBlockY(); //height - int targetZ = pt.getBlockZ(); //depth + int targetX = pt.x(); //wide + int targetY = pt.y(); //height + int targetZ = pt.z(); //depth if (targetY < minY || targetY > maxY) { return false; @@ -384,12 +384,12 @@ public class Polygonal2DRegion extends AbstractRegion implements FlatRegion { long crossproduct; int i; - int xOld = points.get(npoints - 1).getBlockX(); - int zOld = points.get(npoints - 1).getBlockZ(); + int xOld = points.get(npoints - 1).x(); + int zOld = points.get(npoints - 1).z(); for (i = 0; i < npoints; ++i) { - xNew = points.get(i).getBlockX(); - zNew = points.get(i).getBlockZ(); + xNew = points.get(i).x(); + zNew = points.get(i).z(); //Check for corner if (xNew == targetX && zNew == targetZ) { return true; @@ -478,7 +478,7 @@ public class Polygonal2DRegion extends AbstractRegion implements FlatRegion { Iterator it = pts.iterator(); while (it.hasNext()) { BlockVector2 current = it.next(); - sb.append("(").append(current.getBlockX()).append(", ").append(current.getBlockZ()).append(")"); + sb.append("(").append(current.x()).append(", ").append(current.z()).append(")"); if (it.hasNext()) { sb.append(" - "); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java index d2fa35310..e8c6da179 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java @@ -235,15 +235,15 @@ public interface Region extends Iterable, Cloneable, IBatchProcess default boolean isGlobal() { BlockVector3 pos1 = getMinimumPoint(); BlockVector3 pos2 = getMaximumPoint(); - return pos1.getBlockX() == Integer.MIN_VALUE && pos1.getBlockZ() == Integer.MIN_VALUE && pos2.getBlockX() == Integer.MAX_VALUE && pos2 - .getBlockZ() == Integer.MAX_VALUE - && pos1.getBlockY() <= WorldEdit + return pos1.x() == Integer.MIN_VALUE && pos1.z() == Integer.MIN_VALUE && pos2.x() == Integer.MAX_VALUE && pos2 + .z() == Integer.MAX_VALUE + && pos1.y() <= WorldEdit .getInstance() .getPlatformManager() .queryCapability( Capability.WORLD_EDITING) .versionMinY() - && pos2.getBlockY() >= WorldEdit + && pos2.y() >= WorldEdit .getInstance() .getPlatformManager() .queryCapability(Capability.WORLD_EDITING) @@ -251,11 +251,11 @@ public interface Region extends Iterable, Cloneable, IBatchProcess } default int getMinimumY() { - return getMinimumPoint().getY(); + return getMinimumPoint().y(); } default int getMaximumY() { - return getMaximumPoint().getY(); + return getMaximumPoint().y(); } default void filter( @@ -385,7 +385,7 @@ public interface Region extends Iterable, Cloneable, IBatchProcess int tz = bz + 15; BlockVector3 min = getMinimumPoint(); BlockVector3 max = getMaximumPoint(); - return tx >= min.getX() && bx <= max.getX() && tz >= min.getZ() && bz <= max.getZ(); + return tx >= min.x() && bx <= max.x() && tz >= min.z() && bz <= max.z(); } @Override @@ -397,7 +397,7 @@ public interface Region extends Iterable, Cloneable, IBatchProcess BlockVector3 min = getMinimumPoint(); BlockVector3 max = getMaximumPoint(); - if (tx >= min.getX() && bx <= max.getX() && tz >= min.getZ() && bz <= max.getZ()) { + if (tx >= min.x() && bx <= max.x() && tz >= min.z() && bz <= max.z()) { // contains some boolean processExtra = false; for (int layer = getMinimumY() >> 4; layer <= getMaximumY() >> 4; layer++) { @@ -451,7 +451,7 @@ public interface Region extends Iterable, Cloneable, IBatchProcess BlockVector3 min = getMinimumPoint(); BlockVector3 max = getMaximumPoint(); - if (tx >= min.getX() && bx <= max.getX() && tz >= min.getZ() && bz <= max.getZ()) { + if (tx >= min.x() && bx <= max.x() && tz >= min.z() && bz <= max.z()) { // contains some boolean processExtra = false; for (int layer = getMinimumY() >> 4; layer <= getMaximumY() >> 4; layer++) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java index 7a3e91343..c1a81834c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java @@ -168,7 +168,7 @@ public class RegionIntersection extends AbstractRegion { for (Region region : regions) { BlockVector3 regMin = region.getMinimumPoint(); BlockVector3 regMax = region.getMaximumPoint(); - if (tx >= regMin.getX() && bx <= regMax.getX() && tz >= regMin.getZ() && bz <= regMax.getZ()) { + if (tx >= regMin.x() && bx <= regMax.x() && tz >= regMin.z() && bz <= regMax.z()) { intersecting.add(region); } } @@ -204,7 +204,7 @@ public class RegionIntersection extends AbstractRegion { for (Region region : regions) { BlockVector3 regMin = region.getMinimumPoint(); BlockVector3 regMax = region.getMaximumPoint(); - if (tx >= regMin.getX() && bx <= regMax.getX() && tz >= regMin.getZ() && bz <= regMax.getZ()) { + if (tx >= regMin.x() && bx <= regMax.x() && tz >= regMin.z() && bz <= regMax.z()) { return region.processSet(chunk, get, set, true); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Regions.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Regions.java index 040ec2803..d562190cb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Regions.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Regions.java @@ -35,7 +35,7 @@ public final class Regions { * @return the Y coordinate */ public static double minimumY(Region region) { - return region.getMinimumPoint().getY(); + return region.getMinimumPoint().y(); } /** @@ -46,7 +46,7 @@ public final class Regions { * @return the Y coordinate */ public static double maximumY(Region region) { - return region.getMaximumPoint().getY(); + return region.getMaximumPoint().y(); } /** @@ -57,7 +57,7 @@ public final class Regions { * @return the Y coordinate */ public static int minimumBlockY(Region region) { - return region.getMinimumPoint().getBlockY(); + return region.getMinimumPoint().y(); } /** @@ -68,7 +68,7 @@ public final class Regions { * @return the Y coordinate */ public static int maximumBlockY(Region region) { - return region.getMaximumPoint().getBlockY(); + return region.getMaximumPoint().y(); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/TransformRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/TransformRegion.java index b2471af32..782fcebae 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/TransformRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/TransformRegion.java @@ -119,17 +119,17 @@ public class TransformRegion extends AbstractRegion { @Override public int getWidth() { - return getMaximumPoint().subtract(getMinimumPoint()).getBlockX() + 1; + return getMaximumPoint().subtract(getMinimumPoint()).x() + 1; } @Override public int getHeight() { - return getMaximumPoint().subtract(getMinimumPoint()).getBlockY() + 1; + return getMaximumPoint().subtract(getMinimumPoint()).y() + 1; } @Override public int getLength() { - return getMaximumPoint().subtract(getMinimumPoint()).getBlockZ() + 1; + return getMaximumPoint().subtract(getMinimumPoint()).z() + 1; } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/factory/CylinderRegionFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/factory/CylinderRegionFactory.java index 386700b1e..67112c68c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/factory/CylinderRegionFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/factory/CylinderRegionFactory.java @@ -37,8 +37,8 @@ public class CylinderRegionFactory implements RegionFactory { return new CylinderRegion( position, Vector2.at(size, size), - position.getBlockY() - (int) (height / 2), - position.getBlockY() + (int) (height / 2) + position.y() - (int) (height / 2), + position.y() + (int) (height / 2) ); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegion3DIterator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegion3DIterator.java index e7ae99340..12c5f90d9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegion3DIterator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegion3DIterator.java @@ -68,7 +68,7 @@ public class FlatRegion3DIterator implements Iterator { throw new NoSuchElementException(); } - BlockVector3 current = BlockVector3.at(next2D.getBlockX(), nextY, next2D.getBlockZ()); + BlockVector3 current = BlockVector3.at(next2D.x(), nextY, next2D.z()); if (nextY < maxY) { nextY++; } else if (flatIterator.hasNext()) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegionIterator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegionIterator.java index e62c72ecd..3db019499 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegionIterator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/iterator/FlatRegionIterator.java @@ -46,15 +46,15 @@ public class FlatRegionIterator implements Iterator { BlockVector3 min = region.getMinimumPoint(); BlockVector3 max = region.getMaximumPoint(); - this.y = min.getBlockY(); + this.y = min.y(); - this.minX = min.getBlockX(); + this.minX = min.x(); this.nextX = minX; - this.nextZ = min.getBlockZ(); + this.nextZ = min.z(); - this.maxX = max.getBlockX(); - this.maxZ = max.getBlockZ(); + this.maxX = max.x(); + this.maxZ = max.z(); forward(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/iterator/RegionIterator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/iterator/RegionIterator.java index 9e2c9b8e8..54f67b4de 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/iterator/RegionIterator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/iterator/RegionIterator.java @@ -43,14 +43,14 @@ public class RegionIterator implements Iterator { this.region = region; BlockVector3 max = region.getMaximumPoint(); - this.maxX = max.getBlockX(); - this.maxY = max.getBlockY(); - this.maxZ = max.getBlockZ(); + this.maxX = max.x(); + this.maxY = max.y(); + this.maxZ = max.z(); this.min = region.getMinimumPoint(); - this.nextX = min.getBlockX(); - this.nextY = min.getBlockY(); - this.nextZ = min.getBlockZ(); + this.nextX = min.x(); + this.nextY = min.y(); + this.nextZ = min.z(); forward(); } @@ -84,12 +84,12 @@ public class RegionIterator implements Iterator { if (++nextX <= maxX) { return; } - nextX = min.getBlockX(); + nextX = min.x(); if (++nextY <= maxY) { return; } - nextY = min.getBlockY(); + nextY = min.y(); if (++nextZ <= maxZ) { return; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/ConvexPolyhedralRegionSelector.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/ConvexPolyhedralRegionSelector.java index 70471ceae..ac3141c02 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/ConvexPolyhedralRegionSelector.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/ConvexPolyhedralRegionSelector.java @@ -101,8 +101,8 @@ public class ConvexPolyhedralRegionSelector implements RegionSelector, CUIRegion return; } - final int minY = oldRegion.getMinimumPoint().getBlockY(); - final int maxY = oldRegion.getMaximumPoint().getBlockY(); + final int minY = oldRegion.getMinimumPoint().y(); + final int maxY = oldRegion.getMaximumPoint().y(); region = new ConvexPolyhedralRegion(oldRegion.getWorld()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java index 0798b06e6..5a9d3748b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/CylinderRegionSelector.java @@ -115,8 +115,8 @@ public class CylinderRegionSelector implements RegionSelector, CUIRegion { region.setCenter(center.toBlockVector2()); region.setRadius(pos2.toBlockVector2().subtract(center.toBlockVector2()).toVector2()); - region.setMaximumY(Math.max(pos1.getBlockY(), pos2.getBlockY())); - region.setMinimumY(Math.min(pos1.getBlockY(), pos2.getBlockY())); + region.setMaximumY(Math.max(pos1.y(), pos2.y())); + region.setMinimumY(Math.min(pos1.y(), pos2.y())); selectedCenter = true; selectedRadius = true; @@ -164,7 +164,7 @@ public class CylinderRegionSelector implements RegionSelector, CUIRegion { region = new CylinderRegion(region.getWorld()); region.setCenter(position.toBlockVector2()); - region.setY(position.getBlockY()); + region.setY(position.y()); selectedCenter = true; selectedRadius = false; @@ -182,7 +182,7 @@ public class CylinderRegionSelector implements RegionSelector, CUIRegion { final Vector2 minRadius = diff.getMaximum(diff.multiply(-1.0)); region.extendRadius(minRadius); - region.setY(position.getBlockY()); + region.setY(position.y()); selectedRadius = true; @@ -201,8 +201,8 @@ public class CylinderRegionSelector implements RegionSelector, CUIRegion { if (selectedCenter) { player.print(Caption.of( "worldedit.selection.cylinder.explain.secondary", - TextComponent.of(NUMBER_FORMAT.format(region.getRadius().getX())), - TextComponent.of(NUMBER_FORMAT.format(region.getRadius().getZ())), + TextComponent.of(NUMBER_FORMAT.format(region.getRadius().x())), + TextComponent.of(NUMBER_FORMAT.format(region.getRadius().z())), TextComponent.of(region.getVolume()) )); } else { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/ExtendingCuboidRegionSelector.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/ExtendingCuboidRegionSelector.java index 5d74d7ae6..e75f8bbb5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/ExtendingCuboidRegionSelector.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/ExtendingCuboidRegionSelector.java @@ -107,13 +107,13 @@ public class ExtendingCuboidRegionSelector extends CuboidRegionSelector { return false; } - double x1 = Math.min(position.getX(), position1.getX()); - double y1 = Math.min(position.getY(), position1.getY()); - double z1 = Math.min(position.getZ(), position1.getZ()); + double x1 = Math.min(position.x(), position1.x()); + double y1 = Math.min(position.y(), position1.y()); + double z1 = Math.min(position.z(), position1.z()); - double x2 = Math.max(position.getX(), position2.getX()); - double y2 = Math.max(position.getY(), position2.getY()); - double z2 = Math.max(position.getZ(), position2.getZ()); + double x2 = Math.max(position.x(), position2.x()); + double y2 = Math.max(position.y(), position2.y()); + double z2 = Math.max(position.z(), position2.z()); final BlockVector3 o1 = position1; final BlockVector3 o2 = position2; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/Polygonal2DRegionSelector.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/Polygonal2DRegionSelector.java index bf472615a..be9134f15 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/Polygonal2DRegionSelector.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/Polygonal2DRegionSelector.java @@ -96,8 +96,8 @@ public class Polygonal2DRegionSelector implements RegionSelector, CUIRegion { return; } - final int minY = oldRegion.getMinimumPoint().getBlockY(); - final int maxY = oldRegion.getMaximumPoint().getBlockY(); + final int minY = oldRegion.getMinimumPoint().y(); + final int maxY = oldRegion.getMaximumPoint().y(); List points = oldRegion.polygonize(Integer.MAX_VALUE); @@ -118,7 +118,7 @@ public class Polygonal2DRegionSelector implements RegionSelector, CUIRegion { checkNotNull(points); final BlockVector2 pos2D = points.get(0); - pos1 = BlockVector3.at(pos2D.getX(), minY, pos2D.getZ()); + pos1 = BlockVector3.at(pos2D.x(), minY, pos2D.z()); region = new Polygonal2DRegion(world, points, minY, maxY); } @@ -142,7 +142,7 @@ public class Polygonal2DRegionSelector implements RegionSelector, CUIRegion { pos1 = position; region = new Polygonal2DRegion(region.getWorld()); region.addPoint(position); - region.expandY(position.getBlockY()); + region.expandY(position.y()); return true; } @@ -153,7 +153,7 @@ public class Polygonal2DRegionSelector implements RegionSelector, CUIRegion { final List points = region.getPoints(); final BlockVector2 lastPoint = points.get(region.size() - 1); - if (lastPoint.getBlockX() == position.getBlockX() && lastPoint.getBlockZ() == position.getBlockZ()) { + if (lastPoint.x() == position.x() && lastPoint.z() == position.z()) { return false; } @@ -165,7 +165,7 @@ public class Polygonal2DRegionSelector implements RegionSelector, CUIRegion { } region.addPoint(position); - region.expandY(position.getBlockY()); + region.expandY(position.y()); return true; } @@ -228,7 +228,7 @@ public class Polygonal2DRegionSelector implements RegionSelector, CUIRegion { @Override public void learnChanges() { BlockVector2 pt = region.getPoints().get(0); - pos1 = BlockVector3.at(pt.getBlockX(), region.getMinimumPoint().getBlockY(), pt.getBlockZ()); + pos1 = BlockVector3.at(pt.x(), region.getMinimumPoint().y(), pt.z()); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/SphereRegionSelector.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/SphereRegionSelector.java index a0eff3046..7394015ab 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/SphereRegionSelector.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/SphereRegionSelector.java @@ -61,7 +61,7 @@ public class SphereRegionSelector extends EllipsoidRegionSelector { super(oldSelector); if (selectedRadius) { final Vector3 radius = region.getRadius(); - final double radiusScalar = Math.max(Math.max(radius.getX(), radius.getY()), radius.getZ()); + final double radiusScalar = Math.max(Math.max(radius.x(), radius.y()), radius.z()); region.setRadius(Vector3.at(radiusScalar, radiusScalar, radiusScalar)); } } @@ -96,11 +96,11 @@ public class SphereRegionSelector extends EllipsoidRegionSelector { if (isDefined()) { player.print(Caption.of( "worldedit.selection.sphere.explain.secondary-defined", - TextComponent.of(region.getRadius().getX()), + TextComponent.of(region.getRadius().x()), TextComponent.of(region.getVolume()) )); } else { - player.print(Caption.of("worldedit.selection.sphere.explain.secondary", TextComponent.of(region.getRadius().getX()))); + player.print(Caption.of("worldedit.selection.sphere.explain.secondary", TextComponent.of(region.getRadius().x()))); } session.describeCUI(player); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java index 9f2ef87b0..2fb9e6588 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryBiomeShape.java @@ -59,13 +59,13 @@ public abstract class ArbitraryBiomeShape { BlockVector3 min = extent.getMinimumPoint(); BlockVector3 max = extent.getMaximumPoint(); - cacheOffsetX = min.getBlockX() - 1; - cacheOffsetY = min.getBlockY() - 1; - cacheOffsetZ = min.getBlockZ() - 1; + cacheOffsetX = min.x() - 1; + cacheOffsetY = min.y() - 1; + cacheOffsetZ = min.z() - 1; - cacheSizeX = max.getX() - cacheOffsetX + 2; - cacheSizeY = max.getY() - cacheOffsetY + 2; - cacheSizeZ = max.getZ() - cacheOffsetZ + 2; + cacheSizeX = max.x() - cacheOffsetX + 2; + cacheSizeY = max.y() - cacheOffsetY + 2; + cacheSizeZ = max.z() - cacheOffsetZ + 2; cache = new BiomeType[cacheSizeX * cacheSizeY * cacheSizeZ]; isCached = new BitSet(cache.length); @@ -128,9 +128,9 @@ public abstract class ArbitraryBiomeShape { int affected = 0; for (BlockVector3 position : getExtent()) { - int x = position.getBlockX(); - int y = position.getBlockY(); - int z = position.getBlockZ(); + int x = position.x(); + int y = position.y(); + int z = position.z(); if (!hollow) { final BiomeType material = getBiome(x, y, z, baseBiome); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryShape.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryShape.java index 4feff6b8f..dbb516b1b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryShape.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryShape.java @@ -59,13 +59,13 @@ public abstract class ArbitraryShape { BlockVector3 min = extent.getMinimumPoint(); BlockVector3 max = extent.getMaximumPoint(); - cacheOffsetX = min.getBlockX() - 1; - cacheOffsetY = min.getBlockY() - 1; - cacheOffsetZ = min.getBlockZ() - 1; + cacheOffsetX = min.x() - 1; + cacheOffsetY = min.y() - 1; + cacheOffsetZ = min.z() - 1; - cacheSizeX = max.getX() - cacheOffsetX + 2; - cacheSizeY = max.getY() - cacheOffsetY + 2; - cacheSizeZ = max.getZ() - cacheOffsetZ + 2; + cacheSizeX = max.x() - cacheOffsetX + 2; + cacheSizeY = max.y() - cacheOffsetY + 2; + cacheSizeZ = max.z() - cacheOffsetZ + 2; cache = new byte[cacheSizeX * cacheSizeY * cacheSizeZ]; } @@ -98,9 +98,9 @@ public abstract class ArbitraryShape { int affected = 0; for (BlockVector3 position : getExtent()) { - int x = position.getBlockX(); - int y = position.getBlockY(); - int z = position.getBlockZ(); + int x = position.x(); + int y = position.y(); + int z = position.z(); if (!hollow) { BaseBlock material = getMaterial(x, y, z, pattern.applyBlock(position)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/Direction.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/Direction.java index d117ff328..c10312503 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/Direction.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/Direction.java @@ -84,7 +84,7 @@ public enum Direction { } Direction(Vector3 vector, int flags, int left, int right) { - this.blockPoint = BlockVector3.at(Math.signum(vector.getX()), Math.signum(vector.getY()), Math.signum(vector.getZ())); + this.blockPoint = BlockVector3.at(Math.signum(vector.x()), Math.signum(vector.y()), Math.signum(vector.z())); this.direction = vector.normalize(); this.flags = flags; this.left = left; @@ -104,27 +104,27 @@ public enum Direction { } public double getX() { - return direction.getX(); + return direction.x(); } public double getY() { - return direction.getY(); + return direction.y(); } public double getZ() { - return direction.getZ(); + return direction.z(); } public int getBlockX() { - return blockPoint.getX(); + return blockPoint.x(); } public int getBlockY() { - return blockPoint.getY(); + return blockPoint.y(); } public int getBlockZ() { - return blockPoint.getZ(); + return blockPoint.z(); } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TargetBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TargetBlock.java index 01444f269..557709931 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TargetBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TargetBlock.java @@ -223,15 +223,15 @@ public class TargetBlock { curDistance += checkDistance; targetPosDouble = offset.add( - targetPosDouble.getX(), - targetPosDouble.getY(), - targetPosDouble.getZ() + targetPosDouble.x(), + targetPosDouble.y(), + targetPosDouble.z() ); targetPos = targetPosDouble.toBlockPoint(); } while (curDistance <= maxDistance - && targetPos.getBlockX() == prevPos.getBlockX() - && targetPos.getBlockY() == prevPos.getBlockY() - && targetPos.getBlockZ() == prevPos.getBlockZ()); + && targetPos.x() == prevPos.x() + && targetPos.y() == prevPos.y() + && targetPos.z() == prevPos.z()); if (curDistance > maxDistance) { return null; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java index cf5c05278..f529b6c5e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java @@ -135,9 +135,9 @@ public final class TreeGenerator { public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { //FAWE start - perform sanity check on generation location if (editSession - .getBlockType(pos.getX(), pos.getY(), pos.getZ()) + .getBlockType(pos.x(), pos.y(), pos.z()) .getMaterial() - .isAir() && canGenerateOn(editSession.getBlockType(pos.getX(), pos.getY() - 1, pos.getZ()))) { + .isAir() && canGenerateOn(editSession.getBlockType(pos.x(), pos.y() - 1, pos.z()))) { makePineTree(editSession, pos); return true; } @@ -151,7 +151,7 @@ public final class TreeGenerator { //FAWE start - ensure canGenerateOn is called. // chorus plants have to generate starting in the end stone itself, not the air above the ground BlockVector3 down = pos.subtract(0, 1, 0); - if (!canGenerateOn(editSession.getBlockType(down.getX(), down.getY(), down.getZ()))) { + if (!canGenerateOn(editSession.getBlockType(down.x(), down.y(), down.z()))) { return false; } return editSession.getWorld().generateTree(this, editSession, down); @@ -212,9 +212,9 @@ public final class TreeGenerator { public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { //FAWE start - check for ability for tree to generate on block if (editSession - .getBlockType(pos.getX(), pos.getY(), pos.getZ()) + .getBlockType(pos.x(), pos.y(), pos.z()) .getMaterial() - .isAir() && canGenerateOn(editSession.getBlockType(pos.getX(), pos.getY() - 1, pos.getZ()))) { + .isAir() && canGenerateOn(editSession.getBlockType(pos.x(), pos.y() - 1, pos.z()))) { return editSession.getWorld().generateTree(this, editSession, pos); } return false; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/BlockMap.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/BlockMap.java index 43c175dbc..a17f6a04f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/BlockMap.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/BlockMap.java @@ -85,15 +85,15 @@ public class BlockMap extends AbstractMap { private static final int BITS_6 = mask(6); private static long toGroupKey(BlockVector3 location) { - return ((location.getX() >>> 6) & BITS_20) - | (((location.getZ() >>> 6) & BITS_20) << 20) - | (((location.getY() >>> 8) & BITS_24) << (20 + 20)); + return ((location.x() >>> 6) & BITS_20) + | (((location.z() >>> 6) & BITS_20) << 20) + | (((location.y() >>> 8) & BITS_24) << (20 + 20)); } private static int toInnerKey(BlockVector3 location) { - return (location.getX() & BITS_6) - | ((location.getZ() & BITS_6) << 6) - | ((location.getY() & BITS_8) << (6 + 6)); + return (location.x() & BITS_6) + | ((location.z() & BITS_6) << 6) + | ((location.y() & BITS_8) << (6 + 6)); } private static final long GROUP_X = BITS_20; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/VectorPositionList.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/VectorPositionList.java index 3a2759e67..3e725712d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/VectorPositionList.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/VectorPositionList.java @@ -46,9 +46,9 @@ class VectorPositionList implements PositionList { @Override public void add(BlockVector3 vector) { - delegateX.add(vector.getX()); - delegateY.add(vector.getY()); - delegateZ.add(vector.getZ()); + delegateX.add(vector.x()); + delegateY.add(vector.y()); + delegateZ.add(vector.z()); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java index 908e0bac6..ccf8d8535 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -184,7 +184,7 @@ public class NullWorld extends AbstractWorld { @Override public BlockState getBlock(BlockVector3 position) { - return this.getBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + return this.getBlock(position.x(), position.y(), position.z()); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java index 5e4292cd4..5535f4305 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java @@ -130,9 +130,9 @@ public class AnvilChunk implements Chunk { } private int getBlockID(BlockVector3 position) throws DataException { - int x = position.getX() - rootX * 16; - int y = position.getY(); - int z = position.getZ() - rootZ * 16; + int x = position.x() - rootX * 16; + int y = position.y(); + int z = position.z() - rootZ * 16; int section = y >> 4; if (section < 0 || section >= blocks.length) { @@ -163,9 +163,9 @@ public class AnvilChunk implements Chunk { } private int getBlockData(BlockVector3 position) throws DataException { - int x = position.getX() - rootX * 16; - int y = position.getY(); - int z = position.getZ() - rootZ * 16; + int x = position.x() - rootX * 16; + int y = position.y(); + int z = position.z() - rootZ * 16; int section = y >> 4; int yIndex = y & 0x0F; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java index 9b0d764f1..31bb7606c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java @@ -231,9 +231,9 @@ public class AnvilChunk13 implements Chunk { @Override public BaseBlock getBlock(BlockVector3 position) throws DataException { //FAWE start - simplified - int x = position.getX() & 15; - int y = position.getY(); - int z = position.getZ() & 15; + int x = position.x() & 15; + int y = position.y(); + int z = position.z() & 15; //FAWE end int section = y >> 4; @@ -261,8 +261,8 @@ public class AnvilChunk13 implements Chunk { if (biomes == null) { populateBiomes(); } - int rx = position.getX() & 15; - int rz = position.getZ() & 15; + int rx = position.x() & 15; + int rz = position.z() & 15; return biomes[rz << 4 | rx]; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk15.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk15.java index 7565f66c1..60b9d9617 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk15.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk15.java @@ -60,9 +60,9 @@ public class AnvilChunk15 extends AnvilChunk13 { if (biomes == null) { populateBiomes(); } - int x = (position.getX() & 15) >> 2; - int y = position.getY() >> 2; - int z = (position.getZ() & 15) >> 2; + int x = (position.x() & 15) >> 2; + int y = position.y() >> 2; + int z = (position.z() & 15) >> 2; return biomes[y << 4 | z << 2 | x]; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk17.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk17.java index a6fa95b53..6d366c295 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk17.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk17.java @@ -234,9 +234,9 @@ public class AnvilChunk17 implements Chunk { @Override public BaseBlock getBlock(BlockVector3 position) throws DataException { - int x = position.getX() & 15; - int y = position.getY(); - int z = position.getZ() & 15; + int x = position.x() & 15; + int y = position.y(); + int z = position.z() & 15; int section = y >> 4; int yIndex = y & 0x0F; @@ -262,9 +262,9 @@ public class AnvilChunk17 implements Chunk { if (biomes == null) { populateBiomes(); } - int x = (position.getX() & 15) >> 2; - int y = (position.getY() - (minSectionPosition << 4)) >> 2; // normalize - int z = (position.getZ() & 15) >> 2; + int x = (position.x() & 15) >> 2; + int y = (position.y() - (minSectionPosition << 4)) >> 2; // normalize + int z = (position.z() & 15) >> 2; return biomes[y << 4 | z << 2 | x]; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java index bb18e8ed5..4fa50629e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java @@ -232,9 +232,9 @@ public class AnvilChunk18 implements Chunk { @Override public BaseBlock getBlock(BlockVector3 position) throws DataException { - int x = position.getX() & 15; - int y = position.getY(); - int z = position.getZ() & 15; + int x = position.x() & 15; + int y = position.y(); + int z = position.z() & 15; int section = y >> 4; int yIndex = y & 0x0F; @@ -259,10 +259,10 @@ public class AnvilChunk18 implements Chunk { if (biomes == null) { populateBiomes(); } - int x = (position.getX() & 15) >> 2; - int y = (position.getY() & 15) >> 2; - int z = (position.getZ() & 15) >> 2; - int section = position.getY() >> 4; + int x = (position.x() & 15) >> 2; + int y = (position.y() & 15) >> 2; + int z = (position.z() & 15) >> 2; + int section = position.y() >> 4; BiomeType[] sectionBiomes = biomes.get(section); if (sectionBiomes.length == 1) { return sectionBiomes[0]; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java index aabf38ac9..7edb163e3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java @@ -162,15 +162,15 @@ public class OldChunk implements Chunk { @Override public BaseBlock getBlock(BlockVector3 position) throws DataException { - if (position.getY() >= 128) { + if (position.y() >= 128) { return BlockTypes.VOID_AIR.getDefaultState().toBaseBlock(); } int id; int dataVal; - int x = position.getX() - rootX * 16; - int y = position.getY(); - int z = position.getZ() - rootZ * 16; + int x = position.x() - rootX * 16; + int y = position.y(); + int z = position.z() - rootZ * 16; int index = y + (z * 128 + (x * 128 * 16)); try { id = blocks[index]; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java index 0d86679cf..3e3201fb6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java @@ -114,9 +114,9 @@ public class SnapshotRestore { // First, we need to group points by chunk so that we only need // to keep one chunk in memory at any given moment - for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) { - for (int y = min.getBlockY(); y <= max.getBlockY(); ++y) { - for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) { + for (int x = min.x(); x <= max.x(); ++x) { + for (int y = min.y(); y <= max.y(); ++y) { + for (int z = min.z(); z <= max.z(); ++z) { BlockVector3 pos = BlockVector3.at(x, y, z); checkAndAddBlock(pos); } @@ -185,7 +185,7 @@ public class SnapshotRestore { try { editSession.setBlock(pos, chunk.getBlock(pos)); //FAWE start - biome and entity restore - if (restoreBiomes && (pos.getX() & 3) == 0 && (pos.getY() & 3) == 0 && (pos.getZ() & 3) == 0) { + if (restoreBiomes && (pos.x() & 3) == 0 && (pos.y() & 3) == 0 && (pos.z() & 3) == 0) { editSession.setBiome(pos, chunk.getBiome(pos)); } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotRestore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotRestore.java index 9493fc76f..5f9880fc0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotRestore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotRestore.java @@ -109,9 +109,9 @@ public class SnapshotRestore { // First, we need to group points by chunk so that we only need // to keep one chunk in memory at any given moment - for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) { - for (int y = min.getBlockY(); y <= max.getBlockY(); ++y) { - for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) { + for (int x = min.x(); x <= max.x(); ++x) { + for (int y = min.y(); y <= max.y(); ++y) { + for (int z = min.z(); z <= max.z(); ++z) { BlockVector3 pos = BlockVector3.at(x, y, z); checkAndAddBlock(pos); } @@ -181,7 +181,7 @@ public class SnapshotRestore { try { editSession.setBlock(pos, chunk.getBlock(pos)); //FAWE start - biome and entity restore - if (restoreBiomes && (pos.getX() & 3) == 0 && (pos.getY() & 3) == 0 && (pos.getZ() & 3) == 0) { + if (restoreBiomes && (pos.x() & 3) == 0 && (pos.y() & 3) == 0 && (pos.z() & 3) == 0) { editSession.setBiome(pos, chunk.getBiome(pos)); } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java index 6b8de78fc..6b42ba727 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java @@ -73,7 +73,7 @@ public abstract class ChunkStore implements Closeable { * @return chunk coordinates */ public static BlockVector2 toChunk(BlockVector3 position) { - return BlockVector2.at(position.getX() >> CHUNK_SHIFTS, position.getZ() >> CHUNK_SHIFTS); + return BlockVector2.at(position.x() >> CHUNK_SHIFTS, position.z() >> CHUNK_SHIFTS); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/LegacyChunkStore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/LegacyChunkStore.java index 5e534765a..0159c3880 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/LegacyChunkStore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/LegacyChunkStore.java @@ -44,8 +44,8 @@ public abstract class LegacyChunkStore extends ChunkStore { * @return pathname */ public static String getFilename(BlockVector2 position, String separator) { - int x = position.getBlockX(); - int z = position.getBlockZ(); + int x = position.x(); + int z = position.z(); String folder1 = Integer.toString(divisorMod(x, 64), 36); String folder2 = Integer.toString(divisorMod(z, 64), 36); @@ -68,8 +68,8 @@ public abstract class LegacyChunkStore extends ChunkStore { @Override public CompoundTag getChunkTag(BlockVector2 position, World world) throws DataException, IOException { - int x = position.getBlockX(); - int z = position.getBlockZ(); + int x = position.x(); + int z = position.z(); String folder1 = Integer.toString(divisorMod(x, 64), 36); String folder2 = Integer.toString(divisorMod(z, 64), 36); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/McRegionChunkStore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/McRegionChunkStore.java index 5b43de521..a4e06145e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/McRegionChunkStore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/McRegionChunkStore.java @@ -40,8 +40,8 @@ public abstract class McRegionChunkStore extends ChunkStore { * @return the filename */ public static String getFilename(BlockVector2 position) { - int x = position.getBlockX(); - int z = position.getBlockZ(); + int x = position.x(); + int z = position.z(); return "r." + (x >> 5) + "." + (z >> 5) + ".mca"; } 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 193f03b06..88e455200 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 @@ -119,8 +119,8 @@ public class McRegionReader { * @throws DataException if there is an error getting the chunk data */ public synchronized InputStream getChunkInputStream(BlockVector2 position) throws IOException, DataException { - int x = position.getBlockX() & 31; - int z = position.getBlockZ() & 31; + int x = position.x() & 31; + int z = position.z() & 31; int offset = getOffset(x, z); 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 index 444e1db9d..a4dd3062a 100644 --- 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 @@ -74,7 +74,7 @@ class RealExpressionTest extends BaseExpressionTest { 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, + assertEquals(aCase.result, compiled.evaluate(loc.x(), loc.y(), loc.z()), 0, "Test case " + aCase + " failed (result)" ); aCase.postChecks.accept(compiled); diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/util/RegionOptimizedVectorSorterTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/util/RegionOptimizedVectorSorterTest.java index a1582bf04..11057ca25 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/util/RegionOptimizedVectorSorterTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/util/RegionOptimizedVectorSorterTest.java @@ -100,10 +100,10 @@ public class RegionOptimizedVectorSorterTest { for (int i = 0; i < toSort.size() - 1; i++) { BlockVector3 curr = toSort.get(i); BlockVector3 next = toSort.get(i + 1); - int currChunkX = curr.getX() >> 4; - int nextChunkX = next.getX() >> 4; - int currChunkZ = curr.getZ() >> 4; - int nextChunkZ = next.getZ() >> 4; + int currChunkX = curr.x() >> 4; + int nextChunkX = next.x() >> 4; + int currChunkZ = curr.z() >> 4; + int nextChunkZ = next.z() >> 4; int currRegionX = currChunkX >> 5; int nextRegionX = nextChunkX >> 5; int currRegionZ = currChunkZ >> 5; @@ -125,7 +125,7 @@ public class RegionOptimizedVectorSorterTest { fail(spaceship + " " + currChunkZ + " chunk z should be less than or equal to " + nextChunkZ); } else if (currChunkZ == nextChunkZ) { - if (curr.getY() < next.getY()) { + if (curr.y() < next.y()) { fail(spaceship + " " + curr + " y should be greater than or equal to " + next); } 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 44962055b..2a16b4373 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 @@ -65,7 +65,7 @@ public class LocationTest { public void testGetX() throws Exception { World world = mock(World.class); Location location = new Location(world, Vector3.at(TEST_VALUE, 0, 0)); - assertEquals(TEST_VALUE, location.getX(), EPSILON); + assertEquals(TEST_VALUE, location.x(), EPSILON); } @Test @@ -80,17 +80,17 @@ public class LocationTest { World world = mock(World.class); Location location1 = new Location(world, Vector3.ZERO); Location location2 = location1.setX(TEST_VALUE); - assertEquals(0, location1.getX(), EPSILON); - assertEquals(TEST_VALUE, location2.getX(), EPSILON); - assertEquals(0, location2.getY(), EPSILON); - assertEquals(0, location2.getZ(), EPSILON); + assertEquals(0, location1.x(), EPSILON); + assertEquals(TEST_VALUE, location2.x(), EPSILON); + assertEquals(0, location2.y(), EPSILON); + assertEquals(0, location2.z(), EPSILON); } @Test public void testGetY() throws Exception { World world = mock(World.class); Location location = new Location(world, Vector3.at(0, TEST_VALUE, 0)); - assertEquals(TEST_VALUE, location.getY(), EPSILON); + assertEquals(TEST_VALUE, location.y(), EPSILON); } @Test @@ -105,17 +105,17 @@ public class LocationTest { World world = mock(World.class); Location location1 = new Location(world, Vector3.ZERO); Location location2 = location1.setY(TEST_VALUE); - assertEquals(0, location1.getY(), EPSILON); - assertEquals(0, location2.getX(), EPSILON); - assertEquals(TEST_VALUE, location2.getY(), EPSILON); - assertEquals(0, location2.getZ(), EPSILON); + assertEquals(0, location1.y(), EPSILON); + assertEquals(0, location2.x(), EPSILON); + assertEquals(TEST_VALUE, location2.y(), EPSILON); + assertEquals(0, location2.z(), EPSILON); } @Test public void testGetZ() throws Exception { World world = mock(World.class); Location location = new Location(world, Vector3.at(0, 0, TEST_VALUE)); - assertEquals(TEST_VALUE, location.getZ(), EPSILON); + assertEquals(TEST_VALUE, location.z(), EPSILON); } @Test @@ -130,10 +130,10 @@ public class LocationTest { World world = mock(World.class); Location location1 = new Location(world, Vector3.ZERO); Location location2 = location1.setZ(TEST_VALUE); - assertEquals(0, location1.getZ(), EPSILON); - assertEquals(0, location2.getX(), EPSILON); - assertEquals(0, location2.getY(), EPSILON); - assertEquals(TEST_VALUE, location2.getZ(), EPSILON); + assertEquals(0, location1.z(), EPSILON); + assertEquals(0, location2.x(), EPSILON); + assertEquals(0, location2.y(), EPSILON); + assertEquals(TEST_VALUE, location2.z(), EPSILON); } @RepeatedTest(value = 5) @@ -141,7 +141,7 @@ public class LocationTest { World world = mock(World.class); long start = System.currentTimeMillis(); BlockVector3 location1 = BlockVector3.ZERO; - BlockVector3.at(location1.getX() + 10, location1.getY() + 10, location1.getZ() + 10); + BlockVector3.at(location1.x() + 10, location1.y() + 10, location1.z() + 10); System.out.println(System.currentTimeMillis() - start + " ms"); } From 5da6c65df610ef276ee1d189d4c40b874d0112b1 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Mon, 27 May 2024 19:33:52 +0100 Subject: [PATCH 259/466] fix: use correct coordinates in BufferedPattern2D and NoiseFilter --- .../core/function/pattern/BufferedPattern2D.java | 2 +- .../java/com/sk89q/worldedit/function/mask/NoiseFilter.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern2D.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern2D.java index 483629af4..7748c8633 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern2D.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern2D.java @@ -33,7 +33,7 @@ public class BufferedPattern2D extends BufferedPattern { @Override public boolean set(BlockVector3 pos) { - return set.add(pos.x(), 0, pos.y()); + return set.add(pos.x(), 0, pos.z()); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java index d0a016639..8dd9c26d9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java @@ -97,7 +97,7 @@ public class NoiseFilter extends AbstractMask { @Override public boolean test(BlockVector3 vector) { //FAWE start - mutable - return noiseGenerator.noise(mutable.setComponents(vector.x(), vector.z(), vector.z())) <= density; + return noiseGenerator.noise(mutable.setComponents(vector.x(), vector.y(), vector.z())) <= density; //FAWE end } From 7635eec2e47f8caf1454f3744c3949990c9cf41e Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 2 Jun 2024 17:11:53 +0200 Subject: [PATCH 260/466] fix: improve how we determine if using FAWE from jenkins (#2754) - SNAPSHOT will usually only be removed if it's a release version - If others remove SNAPSHOT, then they're probably doing their own stuff, just use this as the "release" check - fixes #2744 --- .../com/fastasyncworldedit/core/util/UpdateNotification.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/UpdateNotification.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/UpdateNotification.java index 73ad01361..fdfe7c56c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/UpdateNotification.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/UpdateNotification.java @@ -59,12 +59,12 @@ public class UpdateNotification { Document doc = db.parse(body); faweVersion = doc.getElementsByTagName("lastSuccessfulBuild").item(0).getFirstChild().getTextContent(); FaweVersion faweVersion = Fawe.instance().getVersion(); - if (faweVersion.build == 0 && !faweVersion.snapshot) { + if (faweVersion.build == 0 && faweVersion.snapshot) { LOGGER.warn("You are using a snapshot or a custom version of FAWE. This is not an official build distributed " + "via https://www.spigotmc.org/resources/13932/"); return; } - if (faweVersion.build < Integer.parseInt(UpdateNotification.faweVersion)) { + if (faweVersion.snapshot && faweVersion.build < Integer.parseInt(UpdateNotification.faweVersion)) { hasUpdate = true; int versionDifference = Integer.parseInt(UpdateNotification.faweVersion) - faweVersion.build; LOGGER.warn( From 261ebfa754c1a2e4ffd4e44aa6952e0a5e73b0b1 Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Sun, 2 Jun 2024 18:21:56 +0200 Subject: [PATCH 261/466] feat: schematic share system, add missing Clipboard method for api compat (#2745) * Allow plugins to register new clipboard share destinations (#1707) * Allow plugins to register new clipboard share destinations * Rename file, as per request * Don't use the base enginehub name for EH_pastebin * Address review comments * Fixed wrong usage * Use a second metadata class for clipboard shares * Newline * Address comments * Improve docs * Apply suggestions from code review Co-authored-by: Octavia Togami * Use a consumer so that we handle serialization * Update worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java Co-authored-by: Octavia Togami * Update worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestination.java Co-authored-by: Octavia Togami * Update worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ShareOutputConsumer.java Co-authored-by: Octavia Togami * Update worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ShareOutputConsumer.java Co-authored-by: Octavia Togami * Fixed a lot of random comments * Return a consumer from share rather than a URL, allows the share destination to control output Co-authored-by: Octavia Togami (cherry picked from commit 6e2b0a1df8a6077c3cf8193e38dc9817038bcbe9) * chore: cleanup cherry-pick remainders * chore/feat: add ark as (default) schematic paster / sharing endpoint * chore: default to fast schematic writer in share * chore: re-format strings.json (seems to adjusted indentation when merging) * chore: hopefully fixing strings.json (again) --------- Co-authored-by: Maddy Miller --- .../core/configuration/Settings.java | 7 + .../arkitektonika/ArkitektonikaResponse.java | 4 + .../ArkitektonikaSchematicUploader.java | 58 +++++ .../worldedit/command/ClipboardCommands.java | 7 +- .../worldedit/command/SchematicCommands.java | 224 ++++++++---------- .../argument/ClipboardFormatConverter.java | 76 ++++++ .../ClipboardShareDestinationConverter.java | 72 ++++++ .../platform/PlatformCommandManager.java | 6 +- .../worldedit/extent/clipboard/Clipboard.java | 24 +- .../extent/clipboard/io/ClipboardFormats.java | 6 +- .../BuiltInClipboardShareDestinations.java | 149 ++++++++++++ .../io/share/ClipboardShareDestination.java | 72 ++++++ .../io/share/ClipboardShareDestinations.java | 80 +++++++ .../io/share/ClipboardShareMetadata.java | 49 ++++ .../io/share/ShareOutputProvider.java | 37 +++ .../util/ClipboardTransformBaker.java} | 37 +-- .../src/main/resources/lang/strings.json | 5 + 17 files changed, 764 insertions(+), 149 deletions(-) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/util/arkitektonika/ArkitektonikaResponse.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/util/arkitektonika/ArkitektonikaSchematicUploader.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ClipboardFormatConverter.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ClipboardShareDestinationConverter.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/BuiltInClipboardShareDestinations.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestination.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestinations.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareMetadata.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ShareOutputProvider.java rename worldedit-core/src/main/java/com/sk89q/worldedit/{command/FlattenedClipboardTransform.java => internal/util/ClipboardTransformBaker.java} (79%) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index 33c8c94f0..cf0ba6f35 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -668,6 +668,13 @@ public class Settings extends Config { @Comment({"The web interface for clipboards", " - All schematics are anonymous and private", " - Downloads can be deleted by the user", " - Supports clipboard uploads, downloads and saves",}) public String URL = "https://schem.intellectualsites.com/fawe/"; + @Comment({"The url of the backend server (Arkitektonika)"}) + public String ARKITEKTONIKA_BACKEND_URL = "https://api.schematic.cloud/"; + @Comment({"The url used to generate a download link from.", "{key} will be replaced with the generated key"}) + public String ARKITEKTONIKA_DOWNLOAD_URL = "https://schematic.cloud/download/{key}"; + @Comment({"The url used to generate a deletion link from.", "{key} will be replaced with the generated key"}) + public String ARKITEKTONIKA_DELETE_URL = "https://schematic.cloud/delete/{key}"; + @Comment("The maximum amount of time in seconds the plugin can attempt to load images for.") public int MAX_IMAGE_LOAD_TIME = 5; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/arkitektonika/ArkitektonikaResponse.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/arkitektonika/ArkitektonikaResponse.java new file mode 100644 index 000000000..821751c2a --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/arkitektonika/ArkitektonikaResponse.java @@ -0,0 +1,4 @@ +package com.fastasyncworldedit.core.util.arkitektonika; + +public record ArkitektonikaResponse(String downloadKey, String deletionKey) { +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/arkitektonika/ArkitektonikaSchematicUploader.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/arkitektonika/ArkitektonikaSchematicUploader.java new file mode 100644 index 000000000..152bca058 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/arkitektonika/ArkitektonikaSchematicUploader.java @@ -0,0 +1,58 @@ +package com.fastasyncworldedit.core.util.arkitektonika; + +import com.fastasyncworldedit.core.internal.exception.FaweException; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.sk89q.worldedit.extent.clipboard.io.share.ClipboardShareMetadata; +import com.sk89q.worldedit.extent.clipboard.io.share.ShareOutputProvider; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.UUID; + +public class ArkitektonikaSchematicUploader { + + private static final String BOUNDARY_IDENTIFIER = "--"; + private static final HttpClient HTTP_CLIENT = HttpClient.newHttpClient(); + private final String apiUrl; + + public ArkitektonikaSchematicUploader(String apiUrl) { + this.apiUrl = apiUrl.endsWith("/") ? apiUrl.substring(0, apiUrl.length() - 1) : apiUrl; + } + + public ArkitektonikaResponse uploadBlocking(ClipboardShareMetadata meta, ShareOutputProvider provider) throws IOException, + InterruptedException { + String boundary = UUID.randomUUID().toString(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + provider.writeTo(outputStream); + + final HttpRequest.BodyPublisher bodyPublisher = HttpRequest.BodyPublishers.concat( + HttpRequest.BodyPublishers.ofString(BOUNDARY_IDENTIFIER + boundary + "\r\n"), + HttpRequest.BodyPublishers.ofString("Content-Disposition: form-data; name=\"schematic\"; filename=\"" + meta.name() + "." + meta.format().getPrimaryFileExtension() + "\"\r\n\r\n"), + HttpRequest.BodyPublishers.ofByteArray(outputStream.toByteArray()), + HttpRequest.BodyPublishers.ofString("\r\n" + BOUNDARY_IDENTIFIER + boundary + BOUNDARY_IDENTIFIER) + ); + + final HttpResponse response = HTTP_CLIENT.send(HttpRequest.newBuilder() + .uri(URI.create(this.apiUrl + "/upload")) + .header("Content-Type", "multipart/form-data; boundary=\"" + boundary + "\"") + .POST(bodyPublisher).build(), HttpResponse.BodyHandlers.ofString()); + if (response.statusCode() != 200) { + throw new FaweException(TextComponent + .of("Arkitektonika returned status code " + response.statusCode()) + .color(TextColor.RED)); + } + JsonObject json = JsonParser.parseString(response.body()).getAsJsonObject(); + return new ArkitektonikaResponse( + json.get("download_key").getAsString(), + json.get("delete_key").getAsString() + ); + } + +} 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 b4037ba15..8c0b69ec9 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 @@ -340,7 +340,7 @@ public class ClipboardCommands { aliases = {"/download"}, desc = "Downloads your clipboard through the configured web interface" ) - @Deprecated + @Deprecated(forRemoval = true, since = "TODO") @CommandPermissions({"worldedit.clipboard.download"}) public void download( final Actor actor, @@ -402,10 +402,7 @@ public class ClipboardCommands { final Clipboard target; // If we have a transform, bake it into the copy if (!transform.isIdentity()) { - final FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform); - target = new BlockArrayClipboard(result.getTransformedRegion(), actor.getUniqueId()); - target.setOrigin(clipboard.getOrigin()); - Operations.completeLegacy(result.copyTo(target)); + target = clipboard.transform(transform); } else { target = clipboard; } 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 e711e61ee..920a24901 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -26,7 +26,6 @@ import com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder; import com.fastasyncworldedit.core.extent.clipboard.URIClipboardHolder; import com.fastasyncworldedit.core.extent.clipboard.io.schematic.MinecraftStructure; import com.fastasyncworldedit.core.util.MainUtil; -import com.google.common.collect.ImmutableList; import com.google.common.collect.Multimap; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; @@ -38,13 +37,13 @@ import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; -import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.extent.clipboard.io.share.ClipboardShareDestination; +import com.sk89q.worldedit.extent.clipboard.io.share.ClipboardShareMetadata; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Transform; @@ -61,19 +60,15 @@ import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.util.io.Closer; import com.sk89q.worldedit.util.io.file.FilenameException; import org.apache.logging.log4j.Logger; -import com.sk89q.worldedit.util.paste.EngineHubPaste; -import com.sk89q.worldedit.util.paste.PasteMetadata; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.Switch; -import org.enginehub.piston.exception.CommandException; import org.enginehub.piston.exception.StopExecutionException; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -85,11 +80,9 @@ import java.net.URL; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.io.OutputStream; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Base64; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -98,6 +91,7 @@ import java.util.Map; import java.util.Objects; import java.util.UUID; import java.util.concurrent.Callable; +import java.util.function.Consumer; import java.util.concurrent.ThreadLocalRandom; import java.util.function.Function; import java.util.regex.Pattern; @@ -321,7 +315,7 @@ public class SchematicCommands { Actor actor, LocalSession session, @Arg(desc = "File name.") String filename, - //FAWE start - random rotation + //FAWE start - use format-name, random rotation @Arg(desc = "Format name.", def = "") String formatName, @Switch(name = 'r', desc = "Apply random rotation to the clipboard") @@ -445,8 +439,8 @@ public class SchematicCommands { Actor actor, LocalSession session, @Arg(desc = "File name.") String filename, - @Arg(desc = "Format name.", def = "fast") - String formatName, + @Arg(desc = "Format name.", def = "fast") //FAWE: def: sponge -> fast + ClipboardFormat format, @Switch(name = 'f', desc = "Overwrite an existing file.") boolean allowOverwrite, //FAWE start @@ -474,12 +468,6 @@ public class SchematicCommands { dir = new File(dir, actor.getUniqueId().toString()); } - ClipboardFormat format = ClipboardFormats.findByAlias(formatName); - if (format == null) { - actor.print(Caption.of("worldedit.schematic.unknown-format", TextComponent.of(formatName))); - return; - } - boolean other = false; if (filename.contains("../")) { other = true; @@ -551,35 +539,98 @@ public class SchematicCommands { @CommandPermissions({ "worldedit.clipboard.share", "worldedit.schematic.share" }) public void share(Actor actor, LocalSession session, @Arg(desc = "Schematic name. Defaults to name-millis", def = "") - String schematicName, - @Arg(desc = "Format name.", def = "sponge") - String formatName) throws WorldEditException { - if (true) { - throw new UnsupportedOperationException("This feature is currently not implemented"); - } + String schematicName, + @Arg(desc = "Share location", def = "arkitektonika") //FAWE: def: ehpaste -> arkitektonika + ClipboardShareDestination destination, + @Arg(desc = "Format name", def = "fast") //FAWE: def: sponge -> fast + ClipboardFormat format) throws WorldEditException { if (worldEdit.getPlatformManager().queryCapability(Capability.GAME_HOOKS).getDataVersion() == -1) { actor.printError(TranslatableComponent.of("worldedit.schematic.unsupported-minecraft-version")); return; } - ClipboardFormat format = ClipboardFormats.findByAlias(formatName); if (format == null) { - actor.printError(TranslatableComponent.of("worldedit.schematic.unknown-format", TextComponent.of(formatName))); + format = destination.getDefaultFormat(); + } + + if (!destination.supportsFormat(format)) { + actor.printError(Caption.of( //FAWE: TranslatableComponent -> Caption + "worldedit.schematic.share.unsupported-format", + TextComponent.of(destination.getName()), + TextComponent.of(format.getName()) + )); return; } ClipboardHolder holder = session.getClipboard(); - SchematicShareTask task = new SchematicShareTask(actor, format, holder, schematicName); + SchematicShareTask task = new SchematicShareTask(actor, holder, destination, format, schematicName); AsyncCommandBuilder.wrap(task, actor) .registerWithSupervisor(worldEdit.getSupervisor(), "Sharing schematic") .setDelayMessage(TranslatableComponent.of("worldedit.schematic.save.saving")) .setWorkingMessage(TranslatableComponent.of("worldedit.schematic.save.still-saving")) - .onSuccess("Shared", (url -> actor.printInfo(TextComponent.of(url.toExternalForm() + ".schem").clickEvent(ClickEvent.openUrl(url.toExternalForm() + ".schem"))))) + .onSuccess("Shared", (consumer -> consumer.accept(actor))) .onFailure("Failed to share schematic", worldEdit.getPlatformManager().getPlatformCommandManager().getExceptionConverter()) .buildAndExec(worldEdit.getExecutorService()); } + @Command( + name = "delete", + aliases = {"d"}, + desc = "Delete a saved schematic" + ) + @CommandPermissions("worldedit.schematic.delete") + public void delete( + Actor actor, LocalSession session, + @Arg(desc = "File name.") + String filename + ) throws WorldEditException, IOException { + LocalConfiguration config = worldEdit.getConfiguration(); + //FAWE start + File working = worldEdit.getWorkingDirectoryPath(config.saveDir).toFile(); + File dir = Settings.settings().PATHS.PER_PLAYER_SCHEMATICS ? new File(working, actor.getUniqueId().toString()) : working; + List files = new ArrayList<>(); + + if (filename.equalsIgnoreCase("*")) { + files.addAll(getFiles(session.getClipboard())); + } else { + File f = MainUtil.resolveRelative(new File(dir, filename)); + files.add(f); + } + + if (files.isEmpty()) { + actor.print(Caption.of("worldedit.schematic.delete.does-not-exist", TextComponent.of(filename))); + return; + } + for (File f : files) { + if (!MainUtil.isInSubDirectory(working, f) || !f.exists()) { + actor.print(Caption.of("worldedit.schematic.delete.does-not-exist", TextComponent.of(filename))); + continue; + } + if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && !MainUtil.isInSubDirectory(dir, f) && !actor.hasPermission( + "worldedit.schematic.delete.other")) { + actor.print(Caption.of("fawe.error.no-perm", "worldedit.schematic.delete.other")); + continue; + } + if (!deleteFile(f)) { + actor.print(Caption.of("worldedit.schematic.delete.failed", TextComponent.of(filename))); + continue; + } + actor.print(Caption.of("worldedit.schematic.delete.deleted", filename)); + } + //FAWE end + } + + //FAWE start + private boolean deleteFile(File file) { + if (file.delete()) { + new File(file.getParentFile(), "." + file.getName() + ".cached").delete(); + return true; + } + return false; + } + //FAWE end + @Command( name = "formats", aliases = {"listformats", "f"}, @@ -764,68 +815,11 @@ public class SchematicCommands { } - @Command( - name = "delete", - aliases = {"d"}, - desc = "Delete a saved schematic" - ) - @CommandPermissions("worldedit.schematic.delete") - public void delete( - Actor actor, LocalSession session, - @Arg(desc = "File name.") - String filename - ) throws WorldEditException, IOException { - LocalConfiguration config = worldEdit.getConfiguration(); - File working = worldEdit.getWorkingDirectoryPath(config.saveDir).toFile(); - //FAWE start - File dir = Settings.settings().PATHS.PER_PLAYER_SCHEMATICS ? new File(working, actor.getUniqueId().toString()) : working; - List files = new ArrayList<>(); - - if (filename.equalsIgnoreCase("*")) { - files.addAll(getFiles(session.getClipboard())); - } else { - File f = MainUtil.resolveRelative(new File(dir, filename)); - files.add(f); - } - - if (files.isEmpty()) { - actor.print(Caption.of("worldedit.schematic.delete.does-not-exist", TextComponent.of(filename))); - return; - } - for (File f : files) { - if (!MainUtil.isInSubDirectory(working, f) || !f.exists()) { - actor.print(Caption.of("worldedit.schematic.delete.does-not-exist", TextComponent.of(filename))); - continue; - } - if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && !MainUtil.isInSubDirectory(dir, f) && !actor.hasPermission( - "worldedit.schematic.delete.other")) { - actor.print(Caption.of("fawe.error.no-perm", "worldedit.schematic.delete.other")); - continue; - } - if (!deleteFile(f)) { - actor.print(Caption.of("worldedit.schematic.delete.failed", TextComponent.of(filename))); - continue; - } - actor.print(Caption.of("worldedit.schematic.delete.deleted", filename)); - } - //FAWE end - } - - //FAWE start - private boolean deleteFile(File file) { - if (file.delete()) { - new File(file.getParentFile(), "." + file.getName() + ".cached").delete(); - return true; - } - return false; - } - //FAWE end - private static class SchematicLoadTask implements Callable { private final Actor actor; - private final ClipboardFormat format; private final File file; + private final ClipboardFormat format; SchematicLoadTask(Actor actor, File file, ClipboardFormat format) { this.actor = actor; @@ -863,19 +857,10 @@ public class SchematicCommands { this.holder = holder; } - protected void writeToOutputStream(OutputStream outputStream) throws Exception { + protected void writeToOutputStream(OutputStream outputStream) throws IOException, WorldEditException { Clipboard clipboard = holder.getClipboard(); Transform transform = holder.getTransform(); - Clipboard target; - // If we have a transform, bake it into the copy - if (transform.isIdentity()) { - target = clipboard; - } else { - FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform); - target = new BlockArrayClipboard(result.getTransformedRegion()); - target.setOrigin(clipboard.getOrigin()); - Operations.completeLegacy(result.copyTo(target)); - } + Clipboard target = clipboard.transform(transform); try (Closer closer = Closer.create()) { OutputStream stream = closer.register(outputStream); @@ -887,9 +872,10 @@ public class SchematicCommands { } private static class SchematicSaveTask extends SchematicOutputTask { - private File file; + private final Actor actor; + private File file; //FAWE: un-finalize private final boolean overwrite; - private final File rootDir; + private final File rootDir; //FAWE: add root-dir SchematicSaveTask( Actor actor, @@ -900,9 +886,10 @@ public class SchematicCommands { boolean overwrite ) { super(actor, format, holder); + this.actor = actor; this.file = file; - this.rootDir = rootDir; this.overwrite = overwrite; + this.rootDir = rootDir; //FAWE: add root-dir } @Override @@ -975,10 +962,7 @@ public class SchematicCommands { if (transform.isIdentity()) { target = clipboard; } else { - FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform); - target = new BlockArrayClipboard(result.getTransformedRegion()); - target.setOrigin(clipboard.getOrigin()); - Operations.completeLegacy(result.copyTo(target)); + target = clipboard.transform(transform); } try (Closer closer = Closer.create()) { @@ -1062,29 +1046,31 @@ public class SchematicCommands { } } - private static class SchematicShareTask extends SchematicOutputTask { + private static class SchematicShareTask extends SchematicOutputTask> { + private final Actor actor; private final String name; + private final ClipboardShareDestination destination; - SchematicShareTask(Actor actor, ClipboardFormat format, ClipboardHolder holder, String name) { + SchematicShareTask(Actor actor, + ClipboardHolder holder, + ClipboardShareDestination destination, + ClipboardFormat format, + String name) { super(actor, format, holder); + this.actor = actor; this.name = name; + this.destination = destination; } @Override - public URL call() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try { - writeToOutputStream(baos); - } catch (Exception e) { - throw new CommandException(TextComponent.of(e.getMessage()), e, ImmutableList.of()); - } + public Consumer call() throws Exception { + ClipboardShareMetadata metadata = new ClipboardShareMetadata( + format, + this.actor.getName(), + name == null ? actor.getName() + "-" + System.currentTimeMillis() : name + ); - EngineHubPaste pasteService = new EngineHubPaste(); - PasteMetadata metadata = new PasteMetadata(); - metadata.author = this.actor.getName(); - metadata.extension = "schem"; - metadata.name = name == null ? actor.getName() + "-" + System.currentTimeMillis() : name; - return pasteService.paste(new String(Base64.getEncoder().encode(baos.toByteArray()), StandardCharsets.UTF_8), metadata).call(); + return destination.share(metadata, this::writeToOutputStream); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ClipboardFormatConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ClipboardFormatConverter.java new file mode 100644 index 000000000..cfa0a1ed4 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ClipboardFormatConverter.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 General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.command.argument; + +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; +import com.sk89q.worldedit.extent.clipboard.io.share.ClipboardShareDestination; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.util.List; +import java.util.Set; + +import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; + +public class ClipboardFormatConverter implements ArgumentConverter { + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(ClipboardFormat.class), + new ClipboardFormatConverter() + ); + } + + private final TextComponent choices; + + private ClipboardFormatConverter() { + this.choices = TextComponent.of("any clipboard format"); + } + + @Override + public Component describeAcceptableArguments() { + return this.choices; + } + + @Override + public List getSuggestions(String input, InjectedValueAccess context) { + ClipboardShareDestination destination = context.injectedValue(Key.of(ClipboardShareDestination.class)).orElse(null); + + return limitByPrefix(ClipboardFormats.getAll().stream() + .filter(format -> destination == null || destination.supportsFormat(format)) + .map(ClipboardFormat::getAliases) + .flatMap(Set::stream), input); + } + + @Override + public ConversionResult convert(String s, InjectedValueAccess injectedValueAccess) { + ClipboardFormat result = ClipboardFormats.findByAlias(s); + return result == null + ? FailedConversion.from(new IllegalArgumentException("Not a valid schematic format: " + s)) + : SuccessfulConversion.fromSingle(result); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ClipboardShareDestinationConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ClipboardShareDestinationConverter.java new file mode 100644 index 000000000..5af81bb1d --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ClipboardShareDestinationConverter.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 General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.command.argument; + +import com.sk89q.worldedit.extent.clipboard.io.share.ClipboardShareDestination; +import com.sk89q.worldedit.extent.clipboard.io.share.ClipboardShareDestinations; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.util.List; +import java.util.Set; + +import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; + +public class ClipboardShareDestinationConverter implements ArgumentConverter { + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(ClipboardShareDestination.class), + new ClipboardShareDestinationConverter() + ); + } + + private final TextComponent choices; + + private ClipboardShareDestinationConverter() { + this.choices = TextComponent.of("any clipboard share destination"); + } + + @Override + public Component describeAcceptableArguments() { + return this.choices; + } + + @Override + public List getSuggestions(String input, InjectedValueAccess context) { + return limitByPrefix(ClipboardShareDestinations.getAll().stream() + .map(ClipboardShareDestination::getAliases) + .flatMap(Set::stream), input); + } + + @Override + public ConversionResult convert(String s, InjectedValueAccess injectedValueAccess) { + ClipboardShareDestination result = ClipboardShareDestinations.findByAlias(s); + return result == null + ? FailedConversion.from(new IllegalArgumentException("Not a valid clipboard share destination: " + s)) + : SuccessfulConversion.fromSingle(result); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 7b493cf98..b03e4ce54 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -86,6 +86,8 @@ import com.sk89q.worldedit.command.WorldEditCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.command.argument.BooleanConverter; import com.sk89q.worldedit.command.argument.Chunk3dVectorConverter; +import com.sk89q.worldedit.command.argument.ClipboardFormatConverter; +import com.sk89q.worldedit.command.argument.ClipboardShareDestinationConverter; import com.sk89q.worldedit.command.argument.CommaSeparatedValuesConverter; import com.sk89q.worldedit.command.argument.DirectionConverter; import com.sk89q.worldedit.command.argument.DirectionVectorConverter; @@ -174,7 +176,6 @@ import java.util.stream.Stream; import static com.google.common.base.Preconditions.checkNotNull; - /** * Handles the registration and invocation of commands. * @@ -272,6 +273,8 @@ public final class PlatformCommandManager { SideEffectConverter.register(commandManager); HeightConverter.register(commandManager); OffsetConverter.register(worldEdit, commandManager); + ClipboardFormatConverter.register(commandManager); + ClipboardShareDestinationConverter.register(commandManager); //FAWE start commandManager.registerConverter( Key.of(com.sk89q.worldedit.function.pattern.Pattern.class, Annotations.patternList()), @@ -604,7 +607,6 @@ public final class PlatformCommandManager { void registerCommandsWith(Platform platform) { LOGGER.info("Registering commands with " + platform.getClass().getCanonicalName()); - LocalConfiguration config = platform.getConfiguration(); boolean logging = config.logCommands; String path = config.logFile; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java index d52fd1056..4cd2ead97 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java @@ -31,6 +31,7 @@ import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSessionBuilder; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; @@ -40,6 +41,7 @@ import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.internal.util.ClipboardTransformBaker; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.Region; @@ -98,7 +100,7 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl * - {@link DiskOptimizedClipboard} * - {@link CPUOptimizedClipboard} * - {@link MemoryOptimizedClipboard} - * + * * @deprecated Internal use only. Use {@link BlockArrayClipboard#BlockArrayClipboard(Region, UUID)} */ @Deprecated @@ -144,10 +146,9 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl void setOrigin(BlockVector3 origin); /** - * Returns true if the clipboard has biome data. This can be checked since {@link Extent#getBiome(BlockVector2)} + * Returns true if the clipboard has biome data. This can be checked since {@link Extent#getBiome(BlockVector3)} * strongly suggests returning {@link com.sk89q.worldedit.world.biome.BiomeTypes#OCEAN} instead of {@code null} - * if biomes aren't present. However, it might not be desired to set areas to ocean if the clipboard is defaulting - * to ocean, instead of having biomes explicitly set. + * if biomes aren't present. * * @return true if the clipboard has biome data set */ @@ -155,6 +156,21 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl return false; } + /** + * Returns a clipboard with a given transform baked in. + * + *

    + * Note: This method may return the same clipboard object, if a copy is needed then you should check the returned value for identity equality and copy if needed. + *

    + * + * @param transform The transform + * @return The new clipboard + * @throws WorldEditException if the copy encounters an error + */ + default Clipboard transform(Transform transform) throws WorldEditException { + return ClipboardTransformBaker.bakeTransform(this, transform); + } + //FAWE start /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java index 03cce5d80..b69a7a0cc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java @@ -73,7 +73,7 @@ public class ClipboardFormats { checkNotNull(format); for (String key : format.getAliases()) { - String lowKey = key.toLowerCase(Locale.ENGLISH); + String lowKey = key.toLowerCase(Locale.ROOT); ClipboardFormat old = aliasMap.put(lowKey, format); if (old != null) { aliasMap.put(lowKey, old); @@ -83,7 +83,7 @@ public class ClipboardFormats { } } for (String ext : format.getFileExtensions()) { - String lowExt = ext.toLowerCase(Locale.ENGLISH); + String lowExt = ext.toLowerCase(Locale.ROOT); fileExtensionMap.put(lowExt, format); } registeredFormats.add(format); @@ -104,7 +104,7 @@ public class ClipboardFormats { @Nullable public static ClipboardFormat findByAlias(String alias) { checkNotNull(alias); - return aliasMap.get(alias.toLowerCase(Locale.ENGLISH).trim()); + return aliasMap.get(alias.toLowerCase(Locale.ROOT).trim()); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/BuiltInClipboardShareDestinations.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/BuiltInClipboardShareDestinations.java new file mode 100644 index 000000000..981debe4b --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/BuiltInClipboardShareDestinations.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 General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.share; + +import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.util.arkitektonika.ArkitektonikaResponse; +import com.fastasyncworldedit.core.util.arkitektonika.ArkitektonikaSchematicUploader; +import com.google.common.collect.ImmutableSet; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; +import com.sk89q.worldedit.util.paste.EngineHubPaste; +import com.sk89q.worldedit.util.paste.PasteMetadata; + +import java.io.ByteArrayOutputStream; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.function.Consumer; + +/** + * A collection of natively supported clipboard share destinations. + */ +public enum BuiltInClipboardShareDestinations implements ClipboardShareDestination { + + /** + * The EngineHub pastebin service, at https://paste.enginehub.org/ + */ + ENGINEHUB_PASTEBIN("enginehub_paste", "ehpaste") { + @Override + public String getName() { + return "EngineHub Paste"; + } + + @Override + public Consumer share(ClipboardShareMetadata metadata, ShareOutputProvider serializer) throws Exception { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + serializer.writeTo(outputStream); + + PasteMetadata pasteMetadata = new PasteMetadata(); + pasteMetadata.author = metadata.author(); + pasteMetadata.extension = "schem"; + pasteMetadata.name = metadata.name(); + EngineHubPaste pasteService = new EngineHubPaste(); + + URL url = pasteService.paste(new String( + Base64.getEncoder().encode(outputStream.toByteArray()), + StandardCharsets.UTF_8 + ), pasteMetadata).call(); + String urlString = url.toExternalForm() + ".schem"; + return actor -> actor.printInfo(TextComponent.of(urlString).clickEvent(ClickEvent.openUrl(urlString))); + } + + @Override + public ClipboardFormat getDefaultFormat() { + return BuiltInClipboardFormat.SPONGE_SCHEMATIC; + } + + @Override + public boolean supportsFormat(ClipboardFormat format) { + return format == getDefaultFormat(); + } + }, + + //FAWE start - add arkitektonika + ARKITEKTONIKA("arkitektonika", "fawe") { + + private ArkitektonikaSchematicUploader uploader; + + @Override + public String getName() { + return "Arkitektonika"; + } + + @Override + public Consumer share(final ClipboardShareMetadata metadata, final ShareOutputProvider serializer) throws + Exception { + if (uploader == null) { + uploader = new ArkitektonikaSchematicUploader(Settings.settings().WEB.ARKITEKTONIKA_BACKEND_URL); + } + final ArkitektonikaResponse response = uploader.uploadBlocking(metadata, serializer); + final String downloadUrl = Settings.settings().WEB.ARKITEKTONIKA_DOWNLOAD_URL.replace("{key}", response.downloadKey()); + final String deletionUrl = Settings.settings().WEB.ARKITEKTONIKA_DELETE_URL.replace("{key}", response.deletionKey()); + return actor -> { + actor.print(Caption.of( + "worldedit.schematic.share.response.arkitektonika.download", + Caption.of("worldedit.schematic.share.response.arkitektonika.click-here") + .color(TextColor.GREEN).clickEvent(ClickEvent.openUrl(downloadUrl)) + )); + actor.print(Caption.of( + "worldedit.schematic.share.response.arkitektonika.delete", + Caption.of("worldedit.schematic.share.response.arkitektonika.click-here") + .color(TextColor.RED).clickEvent(ClickEvent.openUrl(deletionUrl)) + )); + }; + } + + @Override + public ClipboardFormat getDefaultFormat() { + return BuiltInClipboardFormat.FAST; + } + + @Override + public boolean supportsFormat(final ClipboardFormat format) { + return format == BuiltInClipboardFormat.SPONGE_SCHEMATIC || + format == BuiltInClipboardFormat.FAST || + format == BuiltInClipboardFormat.MCEDIT_SCHEMATIC; + } + }; + //FAWE end + + private final ImmutableSet aliases; + + BuiltInClipboardShareDestinations(String... aliases) { + this.aliases = ImmutableSet.copyOf(aliases); + } + + @Override + public ImmutableSet getAliases() { + return this.aliases; + } + + @Override + public String getName() { + return name(); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestination.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestination.java new file mode 100644 index 000000000..1b0cb9e21 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestination.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 General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.share; + +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; + +import java.util.Set; +import java.util.function.Consumer; + +public interface ClipboardShareDestination { + + /** + * Gets the name of this share destination. + * + * @return The name + */ + String getName(); + + /** + * Get a set of aliases. + * + * @return a set of aliases + */ + Set getAliases(); + + /** + * Share a clipboard output stream and return a URL. + * + *

    + * The serialized schematic can be retrieved by providing an {@link java.io.OutputStream} to {@code serializer}. + *

    + * + * @param metadata The clipboard metadata + * @param serializer A function taking the {@link java.io.OutputStream} + * @return A consumer to provide the actor with the share results + * @throws Exception if it failed to share + */ + Consumer share(ClipboardShareMetadata metadata, ShareOutputProvider serializer) throws Exception; + + /** + * Gets the default clipboard format for this share destination. + * + * @return The default format + */ + ClipboardFormat getDefaultFormat(); + + /** + * Gets whether the share destination supports the given format. + * + * @param format The format + * @return If it's supported + */ + boolean supportsFormat(ClipboardFormat format); +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestinations.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestinations.java new file mode 100644 index 000000000..cf9b408f1 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestinations.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 General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.share; + +import com.sk89q.worldedit.WorldEdit; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +public class ClipboardShareDestinations { + + private static final Map aliasMap = new HashMap<>(); + private static final List registeredDestinations = new ArrayList<>(); + + public static void registerClipboardShareDestination(ClipboardShareDestination destination) { + checkNotNull(destination); + checkState(destination.supportsFormat(destination.getDefaultFormat()), "Destination must accept its default format"); + + for (String key : destination.getAliases()) { + String lowKey = key.toLowerCase(Locale.ROOT); + ClipboardShareDestination old = aliasMap.put(lowKey, destination); + if (old != null) { + aliasMap.put(lowKey, old); + WorldEdit.logger.warn(destination.getClass().getName() + " cannot override existing alias '" + lowKey + "' used by " + old.getClass().getName()); + } + } + registeredDestinations.add(destination); + } + + static { + for (BuiltInClipboardShareDestinations destination : BuiltInClipboardShareDestinations.values()) { + registerClipboardShareDestination(destination); + } + } + + /** + * Find the clipboard format named by the given alias. + * + * @param alias the alias + * @return the format, otherwise null if none is matched + */ + @Nullable + public static ClipboardShareDestination findByAlias(String alias) { + checkNotNull(alias); + return aliasMap.get(alias.toLowerCase(Locale.ROOT).trim()); + } + + public static Collection getAll() { + return Collections.unmodifiableCollection(registeredDestinations); + } + + private ClipboardShareDestinations() { + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareMetadata.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareMetadata.java new file mode 100644 index 000000000..2e5f6c042 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareMetadata.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.share; + +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; + +/** + * Items of metadata about shared clipboards. + */ +public class ClipboardShareMetadata { + private final ClipboardFormat format; + private final String name; + private final String author; + + public ClipboardShareMetadata(ClipboardFormat format, String name, String author) { + this.format = format; + this.name = name; + this.author = author; + } + + public ClipboardFormat format() { + return this.format; + } + + public String name() { + return this.name; + } + + public String author() { + return this.author; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ShareOutputProvider.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ShareOutputProvider.java new file mode 100644 index 000000000..6d7587925 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ShareOutputProvider.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 General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.share; + +import com.sk89q.worldedit.WorldEditException; + +import java.io.IOException; +import java.io.OutputStream; + +@FunctionalInterface +public interface ShareOutputProvider { + + /** + * Provides the share output to {@code stream}. + * + * @throws IOException if it failed + * @throws WorldEditException if WorldEdit failed to serialize to the stream + */ + void writeTo(OutputStream stream) throws IOException, WorldEditException; +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/ClipboardTransformBaker.java similarity index 79% rename from worldedit-core/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/ClipboardTransformBaker.java index d32504ad4..daa969080 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/ClipboardTransformBaker.java @@ -17,13 +17,16 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.command; +package com.sk89q.worldedit.internal.util; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.transform.BlockTransformExtent; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.CombinedTransform; @@ -36,12 +39,10 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Helper class to 'bake' a transform into a clipboard. * - *

    This class needs a better name and may need to be made more generic.

    - * * @see Clipboard * @see Transform */ -public class FlattenedClipboardTransform { +public class ClipboardTransformBaker { private final Clipboard original; private final Transform transform; @@ -52,7 +53,7 @@ public class FlattenedClipboardTransform { * @param original the original clipboard * @param transform the transform */ - private FlattenedClipboardTransform(Clipboard original, Transform transform) { + private ClipboardTransformBaker(Clipboard original, Transform transform) { checkNotNull(original); checkNotNull(transform); this.original = original; @@ -64,7 +65,7 @@ public class FlattenedClipboardTransform { * * @return the transformed region */ - public Region getTransformedRegion() { + private Region getTransformedRegion() { Region region = original.getRegion(); Vector3 minimum = region.getMinimumPoint().toVector3(); Vector3 maximum = region.getMaximumPoint().toVector3(); @@ -73,8 +74,7 @@ public class FlattenedClipboardTransform { new CombinedTransform( new AffineTransform().translate(original.getOrigin().multiply(-1)), transform, - new AffineTransform().translate(original.getOrigin()) - ); + new AffineTransform().translate(original.getOrigin())); Vector3[] corners = new Vector3[]{ minimum, @@ -113,7 +113,7 @@ public class FlattenedClipboardTransform { * @param target the target * @return the operation */ - public Operation copyTo(Extent target) { + private Operation copyTo(Extent target) { //FAWE start Extent extent = original; if (transform != null && !transform.isIdentity()) { @@ -121,11 +121,7 @@ public class FlattenedClipboardTransform { } //FAWE end ForwardExtentCopy copy = new ForwardExtentCopy( - extent, - original.getRegion(), - original.getOrigin(), - target, - original.getOrigin() + extent, original.getRegion(), original.getOrigin(), target, original.getOrigin() ); copy.setTransform(transform); if (original.hasBiomes()) { @@ -140,9 +136,18 @@ public class FlattenedClipboardTransform { * @param original the original clipboard * @param transform the transform * @return a builder + * @throws WorldEditException if an error occurred during copy */ - public static FlattenedClipboardTransform transform(Clipboard original, Transform transform) { - return new FlattenedClipboardTransform(original, transform); + public static Clipboard bakeTransform(Clipboard original, Transform transform) throws WorldEditException { + if (transform.isIdentity()) { + return original; + } + ClipboardTransformBaker baker = new ClipboardTransformBaker(original, transform); + Clipboard target = new BlockArrayClipboard(baker.getTransformedRegion()); + target.setOrigin(original.getOrigin()); + Operations.complete(baker.copyTo(target)); + + return target; } } diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index c343dd623..c67da38d7 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -360,6 +360,11 @@ "worldedit.schematic.save.already-exists": "That schematic already exists. Use the -f flag to overwrite it.", "worldedit.schematic.save.failed-directory": "Could not create folder for schematics!", "worldedit.schematic.save.saving": "(Please wait... saving schematic.)", + "worldedit.schematic.save.still-saving": "(Please wait... still saving schematic.)", + "worldedit.schematic.share.unsupported-format": "The schematic share destination \"{0}\" does not support the \"{1}\" format.", + "worldedit.schematic.share.response.arkitektonika.download" : "Download: {0}", + "worldedit.schematic.share.response.arkitektonika.delete" : "Delete: {0}", + "worldedit.schematic.share.response.arkitektonika.click-here" : "[Click here]", "worldedit.schematic.delete.empty": "Schematic {0} not found!", "worldedit.schematic.delete.does-not-exist": "Schematic {0} does not exist!", "worldedit.schematic.delete.failed": "Deletion of {0} failed! Is it read-only?", From c41e38202c959f6f89c56e945800f16866c0081e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 00:48:40 +0000 Subject: [PATCH 262/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.2.12 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 38f8f3f32..d6bf97dcb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.2.11" +towny = "0.100.2.12" plotsquared = "7.3.8" # Third party From da81530f869e0f3269eeabad89b2a8ed93396c4d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 00:48:46 +0000 Subject: [PATCH 263/466] Update dependency net.kyori:adventure-platform-bukkit to v4.3.3 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d6bf97dcb..12c34eeca 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -22,7 +22,7 @@ bstats = "3.0.2" sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.17.0" -adventure-bukkit = "4.3.2" +adventure-bukkit = "4.3.3" checkerqual = "3.43.0" truezip = "6.8.4" auto-value = "1.10.4" From e044b92d45bad2536b881418cf52b1eab8b2b9ae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 03:30:53 +0000 Subject: [PATCH 264/466] Update dependency paperweight-userdev --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 821b6c52d..c82a5bd55 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240424.165410-174") + the().paperDevBundle("1.20.4-R0.1-20240528.102248-175") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts index 8f97a8454..43bc53f15 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/ - the().paperDevBundle("1.20.6-R0.1-20240526.222003-87") + the().paperDevBundle("1.20.6-R0.1-20240602.222958-106") compileOnly(libs.paperlib) } From 393ed005245bd51f1251a5e62664a237af87d37b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 03:30:58 +0000 Subject: [PATCH 265/466] Update eps1lon/actions-label-merge-conflict action to v3.0.2 --- .github/workflows/label-merge-conflicts.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-merge-conflicts.yaml b/.github/workflows/label-merge-conflicts.yaml index 551b39417..8a2c30125 100644 --- a/.github/workflows/label-merge-conflicts.yaml +++ b/.github/workflows/label-merge-conflicts.yaml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Label conflicting PRs - uses: eps1lon/actions-label-merge-conflict@v3.0.1 + uses: eps1lon/actions-label-merge-conflict@v3.0.2 with: dirtyLabel: "unresolved-merge-conflict" repoToken: "${{ secrets.GITHUB_TOKEN }}" From a82ba31185e9142c8ce0b12d83d2a9d0ad573df6 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sun, 2 Jun 2024 09:23:31 +0100 Subject: [PATCH 266/466] feat: allow NBT on wand items - closes #2383 --- .../core/util/gson/BaseItemAdapter.java | 61 +++++++++++++ .../com/sk89q/worldedit/LocalSession.java | 87 ++++++++++++++----- .../com/sk89q/worldedit/blocks/BaseItem.java | 1 + .../worldedit/command/SelectionCommands.java | 32 ++++--- .../sk89q/worldedit/command/ToolCommands.java | 4 +- .../util/PropertiesConfiguration.java | 4 +- .../worldedit/util/YAMLConfiguration.java | 4 +- .../sk89q/worldedit/util/gson/GsonUtil.java | 3 + 8 files changed, 156 insertions(+), 40 deletions(-) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/BaseItemAdapter.java diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/BaseItemAdapter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/BaseItemAdapter.java new file mode 100644 index 000000000..859ed9194 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/BaseItemAdapter.java @@ -0,0 +1,61 @@ +package com.fastasyncworldedit.core.util.gson; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.util.nbt.TagStringIO; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.item.ItemTypes; + +import java.io.IOException; +import java.lang.reflect.Type; + +public final class BaseItemAdapter implements JsonDeserializer, JsonSerializer { + + @Override + public BaseItem deserialize(JsonElement json, Type type, JsonDeserializationContext cont) throws JsonParseException { + JsonObject jsonObject = json.getAsJsonObject(); + JsonElement id = jsonObject.get("id"); + if (id != null) { + ItemType itemType = ItemTypes.get(id.getAsString()); + if (itemType == null) { + throw new JsonParseException("Could not parse item type `" + id + "`"); + } + return new BaseItem(itemType); + } + ItemType itemType = cont.deserialize(jsonObject.get("itemType").getAsJsonObject(), ItemType.class); + JsonElement nbt = jsonObject.get("nbt"); + if (nbt == null) { + return new BaseItem(itemType); + } + try { + return new BaseItem(itemType, LazyReference.computed(TagStringIO.get().asCompound(nbt.getAsString()))); + } catch (IOException e) { + throw new JsonParseException("Could not deserialize BaseItem", e); + } + } + + @Override + public JsonElement serialize( + final BaseItem baseItem, + final Type type, + final JsonSerializationContext jsonSerializationContext + ) { + JsonObject obj = new JsonObject(); + obj.add("itemType", jsonSerializationContext.serialize(baseItem.getType())); + try { + obj.add("nbt", baseItem.getNbt() == null ? null : new JsonPrimitive(TagStringIO.get().asString(baseItem.getNbt()))); + return obj; + } catch (IOException e) { + throw new JsonParseException("Could not deserialize BaseItem", e); + } + } + +} 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 5a5fa654e..8bf84ab8b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -52,6 +52,7 @@ import com.sk89q.worldedit.command.tool.SelectionWand; import com.sk89q.worldedit.command.tool.SinglePickaxe; import com.sk89q.worldedit.command.tool.Tool; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Locatable; import com.sk89q.worldedit.extent.NullExtent; @@ -80,7 +81,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.experimental.Snapshot; import com.zaxxer.sparsebits.SparseBitSet; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -182,8 +182,10 @@ public class LocalSession implements TextureHolder { private String lastScript; private RegionSelectorType defaultSelector; private boolean useServerCUI = false; // Save this to not annoy players. - private ItemType wandItem; - private ItemType navWandItem; + //FAWE start - allow NBT + private BaseItem wandItem; + private BaseItem navWandItem; + //FAWE end /** * Construct the object. @@ -1199,7 +1201,7 @@ public class LocalSession implements TextureHolder { tool = tools.get(item.getInternalId()); } if (tool == SelectionWand.INSTANCE && !SelectionWand.INSTANCE.canUse(player)) { - tools.remove(wandItem.getInternalId()); + tools.remove(wandItem.getType().getInternalId()); loadDefaults(player, true); // Permissions have changed so redo the player's current tools. return null; } @@ -1253,18 +1255,20 @@ public class LocalSession implements TextureHolder { if (loadDefaults || force) { loadDefaults = false; LocalConfiguration config = WorldEdit.getInstance().getConfiguration(); + ParserContext context = new ParserContext(); + context.setActor(actor); if (wandItem == null) { - wandItem = ItemTypes.parse(config.wandItem); + wandItem = WorldEdit.getInstance().getItemFactory().parseFromInput(config.wandItem, context); } if (navWandItem == null) { - navWandItem = ItemTypes.parse(config.navigationWand); + navWandItem = WorldEdit.getInstance().getItemFactory().parseFromInput(config.navigationWand, context); } synchronized (this.tools) { - if (tools.get(navWandItem.getInternalId()) == null && NavigationWand.INSTANCE.canUse(actor)) { - tools.put(navWandItem.getInternalId(), NavigationWand.INSTANCE); + if (tools.get(navWandItem.getType().getInternalId()) == null && NavigationWand.INSTANCE.canUse(actor)) { + tools.put(navWandItem.getType().getInternalId(), NavigationWand.INSTANCE); } - if (tools.get(wandItem.getInternalId()) == null && SelectionWand.INSTANCE.canUse(actor)) { - tools.put(wandItem.getInternalId(), SelectionWand.INSTANCE); + if (tools.get(wandItem.getType().getInternalId()) == null && SelectionWand.INSTANCE.canUse(actor)) { + tools.put(wandItem.getType().getInternalId(), SelectionWand.INSTANCE); } } } @@ -1334,10 +1338,23 @@ public class LocalSession implements TextureHolder { * @param item the item type * @param tool the tool to set, which can be {@code null} * @throws InvalidToolBindException if the item can't be bound to that item + * @deprecated use {@link #setTool(BaseItem, Tool)} */ + @Deprecated public void setTool(ItemType item, @Nullable Tool tool) throws InvalidToolBindException { - if (item.hasBlockType()) { - throw new InvalidToolBindException(item, Caption.of("worldedit.error.blocks-cant-be-used")); + setTool(new BaseItem(item), tool); + } + + /** + * Set the tool. + * + * @param item the item type + * @param tool the tool to set, which can be {@code null} + * @throws InvalidToolBindException if the item can't be bound to that item + */ + public void setTool(BaseItem item, @Nullable Tool tool) throws InvalidToolBindException { + if (item.getType().hasBlockType()) { + throw new InvalidToolBindException(item.getType(), Caption.of("worldedit.error.blocks-cant-be-used")); } if (tool instanceof SelectionWand) { changeTool(this.wandItem, this.wandItem = item, tool); @@ -1348,7 +1365,7 @@ public class LocalSession implements TextureHolder { setDirty(); return; } - setTool(item.getDefaultState(), tool, null); + setTool(item, tool, null); } public void setTool(Player player, @Nullable Tool tool) throws InvalidToolBindException { @@ -1356,17 +1373,17 @@ public class LocalSession implements TextureHolder { setTool(item, tool, player); } - private void changeTool(ItemType oldType, ItemType newType, Tool newTool) { - if (oldType != null) { + private void changeTool(BaseItem oldItem, BaseItem newItem, Tool newTool) { + if (oldItem != null) { synchronized (this.tools) { - this.tools.remove(oldType.getInternalId()); + this.tools.remove(oldItem.getType().getInternalId()); } } synchronized (this.tools) { if (newTool == null) { - this.tools.remove(newType.getInternalId()); + this.tools.remove(newItem.getType().getInternalId()); } else { - this.tools.put(newType.getInternalId(), newTool); + this.tools.put(newItem.getType().getInternalId(), newTool); } } } @@ -1376,11 +1393,11 @@ public class LocalSession implements TextureHolder { if (type.hasBlockType() && type.getBlockType().getMaterial().isAir()) { throw new InvalidToolBindException(type, Caption.of("worldedit.error.blocks-cant-be-used")); } else if (tool instanceof SelectionWand) { - changeTool(this.wandItem, this.wandItem = item.getType(), tool); + changeTool(this.wandItem, this.wandItem = item, tool); setDirty(); return; } else if (tool instanceof NavigationWand) { - changeTool(this.navWandItem, this.navWandItem = item.getType(), tool); + changeTool(this.navWandItem, this.navWandItem = item, tool); setDirty(); return; } @@ -1877,9 +1894,32 @@ public class LocalSession implements TextureHolder { * Get the preferred wand item for this user, or {@code null} to use the default * * @return item id of wand item, or {@code null} + * @deprecated use {@link #getWandBaseItem()} */ + @Deprecated public String getWandItem() { - return wandItem.getId(); + return wandItem.getType().getId(); + } + + /** + * Get the preferred navigation wand item for this user, or {@code null} to use the default + * + * @return item id of nav wand item, or {@code null} + * @deprecated use {@link #getNavWandBaseItem()} + */ + @Deprecated + public String getNavWandItem() { + return navWandItem.getType().getId(); + } + + //FAWE start + /** + * Get the preferred wand item for this user, or {@code null} to use the default + * + * @return item id of wand item, or {@code null} + */ + public BaseItem getWandBaseItem() { + return wandItem == null ? null : new BaseItem(wandItem.getType(), wandItem.getNbtReference()); } /** @@ -1887,9 +1927,10 @@ public class LocalSession implements TextureHolder { * * @return item id of nav wand item, or {@code null} */ - public String getNavWandItem() { - return navWandItem.getId(); + public BaseItem getNavWandBaseItem() { + return navWandItem == null ? null : new BaseItem(navWandItem.getType(), navWandItem.getNbtReference()); } + //FAWE end /** * Get the last block distribution stored in this session. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java index 1dab627c7..ac8236297 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java @@ -71,6 +71,7 @@ public class BaseItem implements NbtValued { * @param itemType The type to set */ public void setType(ItemType itemType) { + checkNotNull(itemType); this.itemType = itemType; } 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 d8e0943dc..ac13defc3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -30,6 +30,7 @@ import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.command.argument.SelectorChoice; import com.sk89q.worldedit.command.tool.NavigationWand; @@ -38,6 +39,8 @@ import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Locatable; import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits; @@ -325,22 +328,29 @@ public class SelectionCommands { //FAWE start session.loadDefaults(player, true); //FAWE end - String wandId = navWand ? session.getNavWandItem() : session.getWandItem(); - if (wandId == null) { - wandId = navWand ? we.getConfiguration().navigationWand : we.getConfiguration().wandItem; + BaseItem wand = navWand ? session.getNavWandBaseItem() : session.getWandBaseItem(); + if (wand == null) { + String wandId = navWand ? we.getConfiguration().navigationWand : we.getConfiguration().wandItem; + //FAWE start - allow item NBT + ParserContext parserContext = new ParserContext(); + parserContext.setActor(player); + parserContext.setSession(session); + try { + wand = WorldEdit.getInstance().getItemFactory().parseFromInput(wandId, parserContext); + } catch (InputParseException e) { + player.print(Caption.of("worldedit.wand.invalid")); + return; + } } - ItemType itemType = ItemTypes.parse(wandId); - if (itemType == null) { - player.print(Caption.of("worldedit.wand.invalid")); - return; - } - player.giveItem(new BaseItemStack(itemType, 1)); + System.out.println("a "+ wand); + player.giveItem(new BaseItemStack(wand.getType(), wand.getNbtReference(), 1)); + //FAWE end //FAWE start - instance-iate session if (navWand) { - session.setTool(itemType, NavigationWand.INSTANCE); + session.setTool(wand, NavigationWand.INSTANCE); player.print(Caption.of("worldedit.wand.navwand.info")); } else { - session.setTool(itemType, SelectionWand.INSTANCE); + session.setTool(wand, SelectionWand.INSTANCE); player.print(Caption.of("worldedit.wand.selwand.info")); //FAWE end } 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 95499372c..f3be41469 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 @@ -149,7 +149,7 @@ public class ToolCommands { throws InvalidToolBindException { //FAWE start isBrush = session.getTool(player) instanceof BrushTool; - session.setTool(player.getItemInHand(HandSide.MAIN_HAND).getType(), null); + session.setTool(player.getItemInHand(HandSide.MAIN_HAND), null); //FAWE end player.print(Caption.of(isBrush ? "worldedit.brush.none.equip" : "worldedit.tool.none.equip")); } @@ -163,7 +163,7 @@ public class ToolCommands { String translationKey ) throws InvalidToolBindException { BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND); - session.setTool(itemStack.getType(), tool); + session.setTool(itemStack, tool); player.print(Caption.of(translationKey, itemStack.getRichName())); sendUnbindInstruction(player, UNBIND_COMMAND_COMPONENT); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java index 3804be8d3..7bec7c2f5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java @@ -112,7 +112,7 @@ public class PropertiesConfiguration extends LocalConfiguration { logFile = getString("log-file", logFile); logFormat = getString("log-format", logFormat); registerHelp = getBool("register-help", registerHelp); - wandItem = getString("wand-item", wandItem).toLowerCase(Locale.ROOT); + wandItem = getString("wand-item", wandItem); try { wandItem = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(wandItem)).getId(); } catch (Throwable ignored) { @@ -122,7 +122,7 @@ public class PropertiesConfiguration extends LocalConfiguration { useInventory = getBool("use-inventory", useInventory); useInventoryOverride = getBool("use-inventory-override", useInventoryOverride); useInventoryCreativeOverride = getBool("use-inventory-creative-override", useInventoryCreativeOverride); - navigationWand = getString("nav-wand-item", navigationWand).toLowerCase(Locale.ROOT); + navigationWand = getString("nav-wand-item", navigationWand); try { navigationWand = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(navigationWand)).getId(); } catch (Throwable ignored) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java index 7b0cbf4b8..4a5e45713 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java @@ -58,7 +58,7 @@ public class YAMLConfiguration extends LocalConfiguration { profile = config.getBoolean("debug", profile); traceUnflushedSessions = config.getBoolean("debugging.trace-unflushed-sessions", traceUnflushedSessions); - wandItem = convertLegacyItem(config.getString("wand-item", wandItem)).toLowerCase(Locale.ROOT); + wandItem = convertLegacyItem(config.getString("wand-item", wandItem)); defaultChangeLimit = Math.max(-1, config.getInt( "limits.max-blocks-changed.default", defaultChangeLimit)); @@ -130,7 +130,7 @@ public class YAMLConfiguration extends LocalConfiguration { useInventoryCreativeOverride ); - navigationWand = convertLegacyItem(config.getString("navigation-wand.item", navigationWand)).toLowerCase(Locale.ROOT); + navigationWand = convertLegacyItem(config.getString("navigation-wand.item", navigationWand)); navigationWandMaxDistance = config.getInt("navigation-wand.max-distance", navigationWandMaxDistance); navigationUseGlass = config.getBoolean("navigation.use-glass", navigationUseGlass); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java index e5d05ee6d..416fbeaae 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java @@ -19,10 +19,12 @@ package com.sk89q.worldedit.util.gson; +import com.fastasyncworldedit.core.util.gson.BaseItemAdapter; import com.fastasyncworldedit.core.util.gson.ItemTypeAdapter; import com.fastasyncworldedit.core.util.gson.RegionSelectorAdapter; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.RegionSelector; @@ -48,6 +50,7 @@ public final class GsonUtil { //FAWE start gsonBuilder.registerTypeAdapter(RegionSelector.class, new RegionSelectorAdapter()); gsonBuilder.registerTypeAdapter(ItemType.class, new ItemTypeAdapter()); + gsonBuilder.registerTypeAdapter(BaseItem.class, new BaseItemAdapter()); //FAWE end return gsonBuilder; } From 47b0ece3777ae13564575cc6569ed2c34cac40d4 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sun, 2 Jun 2024 09:27:56 +0100 Subject: [PATCH 267/466] Add since tags to new methods --- .../src/main/java/com/sk89q/worldedit/LocalSession.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index 8bf84ab8b..5df95414b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -1351,6 +1351,7 @@ public class LocalSession implements TextureHolder { * @param item the item type * @param tool the tool to set, which can be {@code null} * @throws InvalidToolBindException if the item can't be bound to that item + * @since TODO */ public void setTool(BaseItem item, @Nullable Tool tool) throws InvalidToolBindException { if (item.getType().hasBlockType()) { @@ -1917,6 +1918,7 @@ public class LocalSession implements TextureHolder { * Get the preferred wand item for this user, or {@code null} to use the default * * @return item id of wand item, or {@code null} + * @since TODO */ public BaseItem getWandBaseItem() { return wandItem == null ? null : new BaseItem(wandItem.getType(), wandItem.getNbtReference()); @@ -1926,6 +1928,7 @@ public class LocalSession implements TextureHolder { * Get the preferred navigation wand item for this user, or {@code null} to use the default * * @return item id of nav wand item, or {@code null} + * @since TODO */ public BaseItem getNavWandBaseItem() { return navWandItem == null ? null : new BaseItem(navWandItem.getType(), navWandItem.getNbtReference()); From a7e4d19605484b7eb3f2619ea270114be8fa56cf Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sun, 2 Jun 2024 17:25:32 +0100 Subject: [PATCH 268/466] Remove debug --- .../main/java/com/sk89q/worldedit/command/SelectionCommands.java | 1 - 1 file changed, 1 deletion(-) 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 ac13defc3..d000fcef7 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 @@ -342,7 +342,6 @@ public class SelectionCommands { return; } } - System.out.println("a "+ wand); player.giveItem(new BaseItemStack(wand.getType(), wand.getNbtReference(), 1)); //FAWE end //FAWE start - instance-iate session From 5714a526756e1819b1598f31211e26b48cdd217d Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 5 Jun 2024 21:23:12 +0200 Subject: [PATCH 269/466] fix: correctly trim the max chunk section (#2753) - fixes #2727 - fixes IntellectualSites/Plotsquared#4436 --- .../regions/plotsquared/PlotSquaredFeature.java | 14 ++++++-------- .../core/queue/IBatchProcessor.java | 12 ++++-------- .../com/sk89q/worldedit/regions/CuboidRegion.java | 4 ++-- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java index 9f0916a4b..49955a4fa 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java @@ -1,6 +1,5 @@ package com.fastasyncworldedit.bukkit.regions.plotsquared; -import com.fastasyncworldedit.core.FaweAPI; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.regions.FaweMask; import com.fastasyncworldedit.core.regions.FaweMaskManager; @@ -174,22 +173,21 @@ public class PlotSquaredFeature extends FaweMaskManager { return null; } + final World world = player.getWorld(); + int min = area != null ? area.getMinBuildHeight() : world.getMinY(); + // PlotSquared uses exclusive max height, WorldEdit uses inclusive max height -> subtract 1 + int max = area != null ? Math.min(world.getMaxY(), area.getMaxBuildHeight() - 1) : world.getMaxY(); Region maskedRegion; if (regions.size() == 1) { - final World world = player.getWorld(); - int min = area != null ? area.getMinBuildHeight() : world.getMinY(); - // PlotSquared uses exclusive max height, WorldEdit uses inclusive max height -> subtract 1 - int max = area != null ? Math.min(world.getMaxY(), area.getMaxBuildHeight() - 1) : world.getMaxY(); final CuboidRegion region = regions.iterator().next(); final BlockVector3 pos1 = BlockVector3.at(region.getMinimumX(), min, region.getMinimumZ()); final BlockVector3 pos2 = BlockVector3.at(region.getMaximumX(), max, region.getMaximumZ()); maskedRegion = new CuboidRegion(pos1, pos2); } else { - World world = FaweAPI.getWorld(area.getWorldName()); List weRegions = regions.stream().map( - r -> new CuboidRegion(world, BlockVector3.at(r.getMinimumX(), r.getMinimumY(), r.getMinimumZ()), - BlockVector3.at(r.getMaximumX(), r.getMaximumY(), r.getMaximumZ()) + r -> new CuboidRegion(world, BlockVector3.at(r.getMinimumX(), min, r.getMinimumZ()), + BlockVector3.at(r.getMaximumX(), max, r.getMaximumZ()) )).collect(Collectors.toList()); maskedRegion = new RegionIntersection(world, weRegions); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java index 778f85ce4..4ba91a4f3 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java @@ -58,7 +58,7 @@ public interface IBatchProcessor { /** * Utility method to trim a chunk based on min and max Y (inclusive). * - * @param keepInsideRange if all blocks inside the range (inclusive) should be kept (default) + * @param keepInsideRange if all blocks inside the range (inclusive) should be kept (default), or removed * @return false if chunk is empty of blocks */ default boolean trimY(IChunkSet set, int minY, int maxY, final boolean keepInsideRange) { @@ -74,16 +74,14 @@ public interface IBatchProcessor { for (int i = 0; i < index; i++) { arr[i] = BlockTypesCache.ReservedIDs.__RESERVED__; } - } else { - arr = new char[4096]; + set.setBlocks(layer, arr); } - set.setBlocks(layer, arr); } else { set.setBlocks(layer, null); } } } - for (int layer = maxLayer; layer < set.getMaxSectionPosition(); layer++) { + for (int layer = maxLayer; layer <= set.getMaxSectionPosition(); layer++) { if (set.hasSection(layer)) { if (layer == maxLayer) { char[] arr = set.loadIfPresent(layer); @@ -92,10 +90,8 @@ public interface IBatchProcessor { for (int i = index; i < arr.length; i++) { arr[i] = BlockTypesCache.ReservedIDs.__RESERVED__; } - } else { - arr = new char[4096]; + set.setBlocks(layer, arr); } - set.setBlocks(layer, arr); } else { set.setBlocks(layer, null); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index 8616cbb2b..8e4da9214 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -828,7 +828,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return set; } - for (int layer = get.getMinSectionPosition(); layer < get.getMaxSectionPosition(); layer++) { + for (int layer = get.getMinSectionPosition(); layer <= get.getMaxSectionPosition(); layer++) { if (!set.hasSection(layer)) { continue; } @@ -912,7 +912,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { boolean trimX = lowerX != 0 || upperX != 15; boolean trimZ = lowerZ != 0 || upperZ != 15; - for (int layer = get.getMinSectionPosition(); layer < get.getMaxSectionPosition(); layer++) { + for (int layer = get.getMinSectionPosition(); layer <= get.getMaxSectionPosition(); layer++) { if (!set.hasSection(layer)) { continue; } From c095c492e0264fc19a9d6f453183adf0f9f3f2e7 Mon Sep 17 00:00:00 2001 From: EpicPlayerA10 <62206933+EpicPlayerA10@users.noreply.github.com> Date: Fri, 7 Jun 2024 12:30:31 +0200 Subject: [PATCH 270/466] fix: normalize layer when setting ordinal to ThreadUnsafeCharBlocks (#2764) - fixes #2763 --- .../queue/implementation/blocks/ThreadUnsafeCharBlocks.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java index 54331279f..90ae6b32e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java @@ -222,7 +222,7 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks { } public void set(int x, int y, int z, char value) { - final int layer = y >> 4; + final int layer = (y >> 4) - minSectionPosition; final int index = (y & 15) << 8 | z << 4 | x; try { blocks[layer][index] = value; From ee5d1caa2c568ee40eecc9523453bb132265cfab Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Sat, 8 Jun 2024 10:07:05 +0200 Subject: [PATCH 271/466] Fix more upstream incompatibilities (#2767) * Move more public types to records (cherry picked from commit 35e58895f5379e78b856e8997a593701c6d9db21) * chore: pull in PlacementType * fix: mask reference in NegatedMask * Use records in expression impl (cherry picked from commit 453537c5b4783412aa1b4e982d7b72c637d0db8e) * fix: variable record getter access * chore: add since to Deprecated annotation * chore: revert weird merge in ClientProxy * chore: cleanup remaining deprecations * chore: code-style --------- Co-authored-by: Octavia Togami --- .../java/com/sk89q/worldedit/EditSession.java | 10 +- .../io/share/ClipboardShareMetadata.java | 27 +--- .../worldedit/function/factory/Deform.java | 26 ++-- .../sk89q/worldedit/function/mask/Mask.java | 2 +- .../sk89q/worldedit/function/mask/Masks.java | 18 +-- .../history/change/BiomeChange3D.java | 24 ++-- .../worldedit/history/change/BlockChange.java | 30 +++-- .../exception/ExceptionConverterHelper.java | 14 +-- .../internal/event/InteractionDebouncer.java | 9 +- .../internal/expression/ExecutionData.java | 27 ++-- .../internal/expression/ExpressionHelper.java | 26 ++-- .../internal/expression/Functions.java | 12 +- .../internal/expression/LocalSlot.java | 19 +-- .../internal/expression/SlotTable.java | 2 +- .../expression/invoke/CompilingVisitor.java | 22 ++-- .../internal/expression/invoke/ExecNode.java | 13 +- .../expression/invoke/ExpressionHandles.java | 26 ++-- .../com/sk89q/worldedit/registry/Keyed.java | 22 +++- .../sk89q/worldedit/session/Placement.java | 52 ++++++++ .../worldedit/session/PlacementType.java | 119 ++++++++++++++++++ .../sk89q/worldedit/util/LocatedBlock.java | 48 +++---- .../worldedit/util/report/DataReport.java | 11 +- .../worldedit/world/biome/BiomeType.java | 25 ++-- .../worldedit/world/entity/EntityType.java | 30 ++++- .../worldedit/world/fluid/FluidType.java | 20 ++- .../worldedit/world/gamemode/GameMode.java | 28 +---- .../world/registry/ItemMaterial.java | 37 +++++- .../registry/PassthroughItemMaterial.java | 8 +- .../world/registry/SimpleItemMaterial.java | 20 +-- .../worldedit/world/weather/WeatherType.java | 29 +---- 30 files changed, 435 insertions(+), 321 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/session/Placement.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/session/PlacementType.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 2e5e3c2ef..1469ffb96 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -3082,8 +3082,8 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { ) <= 0) { return null; } - int newType = (int) typeVariable.getValue(); - int newData = (int) dataVariable.getValue(); + int newType = (int) typeVariable.value(); + int newData = (int) dataVariable.value(); if (newType != typeVar || newData != dataVar) { BlockState state = LegacyMapper.getInstance().getBlockFromLegacy(newType, newData); return state == null ? defaultMaterial : state.toBaseBlock(); @@ -3181,9 +3181,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { // transform expression.evaluate(new double[]{scaled.x(), scaled.y(), scaled.z()}, timeout); - int xv = (int) Math.floor(x.getValue() * unit.x() + zero2.x()); - int yv = (int) Math.floor(y.getValue() * unit.y() + zero2.y()); - int zv = (int) Math.floor(z.getValue() * unit.z() + zero2.z()); + int xv = (int) Math.floor(x.value() * unit.x() + zero2.x()); + int yv = (int) Math.floor(y.value() * unit.y() + zero2.y()); + int zv = (int) Math.floor(z.value() * unit.z() + zero2.z()); BlockState get; if (yv >= minY && yv <= maxY) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareMetadata.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareMetadata.java index 2e5f6c042..a670ea7cc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareMetadata.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareMetadata.java @@ -23,27 +23,10 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; /** * Items of metadata about shared clipboards. + * + * @param format the format of the clipboard + * @param name the name of the clipboard + * @param author the author of the clipboard */ -public class ClipboardShareMetadata { - private final ClipboardFormat format; - private final String name; - private final String author; - - public ClipboardShareMetadata(ClipboardFormat format, String name, String author) { - this.format = format; - this.name = name; - this.author = author; - } - - public ClipboardFormat format() { - return this.format; - } - - public String name() { - return this.name; - } - - public String author() { - return this.author; - } +public record ClipboardShareMetadata(ClipboardFormat format, String name, String author) { } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java index b4ccd0a55..6dea78892 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java @@ -167,24 +167,14 @@ public class Deform implements Contextual { ); } - private static final class DeformOperation implements Operation { - - private final Extent destination; - private final Region region; - private final Vector3 zero; - private final Vector3 unit; - private final String expression; - private final int timeout; - - private DeformOperation(Extent destination, Region region, Vector3 zero, Vector3 unit, String expression, int timeout) { - this.destination = destination; - this.region = region; - this.zero = zero; - this.unit = unit; - this.expression = expression; - this.timeout = timeout; - } - + private record DeformOperation( + Extent destination, + Region region, + Vector3 zero, + Vector3 unit, + String expression, //FAWE: Expression -> String + int timeout + ) implements Operation { @Override public Operation resume(RunContext run) throws WorldEditException { try { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java index 3c4cb1378..94141278d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java @@ -87,7 +87,7 @@ public interface Mask { } else if (this instanceof Masks.AlwaysFalse) { return Masks.ALWAYS_TRUE; } else if (this instanceof Masks.NegatedMask) { - return ((Masks.NegatedMask) this).mask; + return ((Masks.NegatedMask) this).mask(); } return new InverseMask(this); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java index d3cb4cad7..478d2732a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java @@ -211,15 +211,7 @@ public final class Masks { } - //FAWE start - protected > private - protected static class NegatedMask implements Mask { - - //FAWE end - protected final Mask mask; - - private NegatedMask(Mask mask) { - this.mask = mask; - } + protected record NegatedMask(Mask mask) implements Mask { @Override public boolean test(BlockVector3 vector) { @@ -245,13 +237,7 @@ public final class Masks { } - private static class NegatedMask2D implements Mask2D { - - private final Mask2D mask; - - private NegatedMask2D(Mask2D mask) { - this.mask = mask; - } + private record NegatedMask2D(Mask2D mask) implements Mask2D { @Override public boolean test(BlockVector2 vector) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java index 74a16e90e..1106899f8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java @@ -33,34 +33,30 @@ import static com.google.common.base.Preconditions.checkNotNull; *

    This biome change does not have an {@link Extent} assigned to it because * one will be taken from the passed {@link UndoContext}. If the context * does not have an extent (it is null), cryptic errors may occur.

    + * + * @param position the position + * @param previous the previous biome + * @param current the current biome */ -public class BiomeChange3D implements Change { - - private final BlockVector3 position; - private final BiomeType previous; - private final BiomeType current; +public record BiomeChange3D(BlockVector3 position, BiomeType previous, BiomeType current) implements Change { /** * Create a new biome change. * - * @param position the position - * @param previous the previous biome - * @param current the current biome */ - public BiomeChange3D(BlockVector3 position, BiomeType previous, BiomeType current) { + public BiomeChange3D { checkNotNull(position); checkNotNull(previous); checkNotNull(current); - this.position = position; - this.previous = previous; - this.current = current; } /** * Get the position. * * @return the position + * @deprecated Use {@link #position()}. */ + @Deprecated(forRemoval = true, since = "TODO") public BlockVector3 getPosition() { return position; } @@ -69,7 +65,9 @@ public class BiomeChange3D implements Change { * Get the previous biome. * * @return the previous biome + * @deprecated Use {@link #previous()}. */ + @Deprecated(forRemoval = true, since = "TODO") public BiomeType getPrevious() { return previous; } @@ -78,7 +76,9 @@ public class BiomeChange3D implements Change { * Get the current biome. * * @return the current biome + * @deprecated Use {@link #current()}. */ + @Deprecated(forRemoval = true, since = "TODO") public BiomeType getCurrent() { return current; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java index ec9bb104d..16fc50e0d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java @@ -34,12 +34,21 @@ import static com.google.common.base.Preconditions.checkNotNull; *

    This block change does not have an {@link Extent} assigned to it because * one will be taken from the passed {@link UndoContext}. If the context * does not have an extent (it is null), cryptic errors may occur.

    + * + * @param position the position + * @param previous the previous block + * @param current the current block */ -public class BlockChange implements Change { +public record BlockChange(BlockVector3 position, BaseBlock previous, BaseBlock current) implements Change { - private final BlockVector3 position; - private final BaseBlock previous; - private final BaseBlock current; + /** + * Create a new block change. + */ + public BlockChange { + checkNotNull(position); + checkNotNull(previous); + checkNotNull(current); + } /** * Create a new block change. @@ -53,19 +62,16 @@ public class BlockChange implements Change { BP previous, BC current ) { - checkNotNull(position); - checkNotNull(previous); - checkNotNull(current); - this.position = position; - this.previous = previous.toBaseBlock(); - this.current = current.toBaseBlock(); + this(position, previous.toBaseBlock(), current.toBaseBlock()); } /** * Get the position. * * @return the position + * @deprecated use {@link #position()} */ + @Deprecated(forRemoval = true, since = "TODO") public BlockVector3 getPosition() { return position; } @@ -74,7 +80,9 @@ public class BlockChange implements Change { * Get the previous block. * * @return the previous block + * @deprecated use {@link #previous()} */ + @Deprecated(forRemoval = true, since = "TODO") public BaseBlock getPrevious() { return previous; } @@ -83,7 +91,9 @@ public class BlockChange implements Change { * Get the current block. * * @return the current block + * @deprecated use {@link #current()} */ + @Deprecated(forRemoval = true, since = "TODO") public BaseBlock getCurrent() { return current; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java index 73f76280e..64e78250a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java @@ -87,16 +87,10 @@ public abstract class ExceptionConverterHelper implements ExceptionConverter { } } - private static class ExceptionHandler implements Comparable { - - final Class cls; - final Method method; - - private ExceptionHandler(Class cls, Method method) { - this.cls = cls; - this.method = method; - } - + private record ExceptionHandler( + Class cls, + Method method + ) implements Comparable { @Override public int compareTo(ExceptionHandler o) { if (cls.equals(o.cls)) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/event/InteractionDebouncer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/event/InteractionDebouncer.java index b33570cd9..37e9442b7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/event/InteractionDebouncer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/event/InteractionDebouncer.java @@ -57,13 +57,6 @@ public class InteractionDebouncer { return Optional.empty(); } - private static class Interaction { - public final long tick; - public final boolean result; - - public Interaction(long tick, boolean result) { - this.tick = tick; - this.result = result; - } + private record Interaction(long tick, boolean result) { } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExecutionData.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExecutionData.java index 1fef5aa81..bcf04b907 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExecutionData.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExecutionData.java @@ -23,36 +23,23 @@ import java.time.Instant; import static java.util.Objects.requireNonNull; -public class ExecutionData { - +public record ExecutionData(SlotTable slots, Functions functions, Instant deadline) { /** - * Special execution context for evaluating constant values. As long as no variables are used, - * it can be considered constant. + * Special execution context for evaluating constant values. As long as no variables are used, it can be considered + * constant. */ public static final ExecutionData CONSTANT_EVALUATOR = new ExecutionData(null, null, Instant.MAX); - private final SlotTable slots; - private final Functions functions; - private final Instant deadline; - - public ExecutionData(SlotTable slots, Functions functions, Instant deadline) { - this.slots = slots; - this.functions = functions; - this.deadline = deadline; - } - - public SlotTable getSlots() { + @Override + public SlotTable slots() { return requireNonNull(slots, "Cannot use variables in a constant"); } - public Functions getFunctions() { + @Override + public Functions functions() { return requireNonNull(functions, "Cannot use functions in a constant"); } - public Instant getDeadline() { - return deadline; - } - public void checkDeadline() { if (Instant.now().isAfter(deadline)) { throw new ExpressionTimeoutException("Calculations exceeded time limit."); 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 index 0afeb6dd3..0521c0a50 100644 --- 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 @@ -40,6 +40,12 @@ public class ExpressionHelper { } } + public static void check(boolean condition, int positionInLine, String message) { + if (!condition) { + throw evalException(positionInLine, message); + } + } + public static int getErrorPosition(Token token) { return token.getCharPositionInLine(); } @@ -49,14 +55,18 @@ public class ExpressionHelper { } public static EvaluationException evalException(Token token, String message) { + return evalException(getErrorPosition(token), message); + } + + public static EvaluationException evalException(int positionInLine, String message) { return new EvaluationException( - getErrorPosition(token), - message + positionInLine, + message ); } - public static void checkIterations(int iterations, ParserRuleContext ctx) { - check(iterations <= 256, ctx, "Loop exceeded 256 iterations"); + public static void checkIterations(int iterations, int positionInLine) { + check(iterations <= 256, positionInLine, "Loop exceeded 256 iterations"); } public static MethodHandle resolveFunction( @@ -72,10 +82,10 @@ public class ExpressionHelper { // last param is the array, turn that varargs int keptParams = nParams - 1; function = function.asCollector( - // collect into the last array - function.type().parameterType(nParams - 1), - // collect the variable args (args over kept) - ctx.args.size() - keptParams + // collect into the last array + function.type().parameterType(nParams - 1), + // collect the variable args (args over kept) + ctx.args.size() - keptParams ); // re-wrap it for the inner arguments function = function.asType(function.type().wrap()); 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 index 6f3a63787..ef219e3f8 100644 --- 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 @@ -211,8 +211,8 @@ public final class Functions { final double cosF = Math.cos(angle); final double sinF = Math.sin(angle); - final double xOld = x.getValue(); - final double yOld = y.getValue(); + final double xOld = x.value(); + final double yOld = y.value(); x.setValue(xOld * cosF - yOld * sinF); y.setValue(xOld * sinF + yOld * cosF); @@ -221,9 +221,9 @@ public final class Functions { } private static double swap(Variable x, Variable y) { - final double tmp = x.getValue(); + final double tmp = x.value(); - x.setValue(y.getValue()); + x.setValue(y.value()); y.setValue(tmp); return 0.0; @@ -391,8 +391,8 @@ public final class Functions { 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; + double ret = ((type.value() == -1 || typeId == type.value()) + && (data.value() == -1 || dataValue == data.value())) ? 1.0 : 0.0; if (type instanceof Variable) { ((Variable) type).setValue(typeId); 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 index 2b02fa036..0b2a5bc48 100644 --- 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 @@ -24,19 +24,7 @@ package com.sk89q.worldedit.internal.expression; */ 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; - } - + record Constant(double value) implements LocalSlot { @Override public String toString() { return String.valueOf(value); @@ -57,7 +45,7 @@ public interface LocalSlot { } @Override - public double getValue() { + public double value() { return value; } @@ -65,9 +53,8 @@ public interface LocalSlot { public String toString() { return String.valueOf(value); } - } - double getValue(); + double value(); } 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 index a94c9dc62..e7090f461 100644 --- 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 @@ -58,7 +58,7 @@ public class SlotTable { public OptionalDouble getSlotValue(String name) { LocalSlot slot = slots.get(name); - return slot == null ? OptionalDouble.empty() : OptionalDouble.of(slot.getValue()); + return slot == null ? OptionalDouble.empty() : OptionalDouble.of(slot.value()); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java index 7645c8413..0c6e87810 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java @@ -106,7 +106,7 @@ class CompilingVisitor extends ExpressionBaseVisitor { if (ctx.parent instanceof ParserRuleContext) { checkHandle(mh, (ParserRuleContext) ctx.parent); } - return new ExecNode(ctx, mh); + return new ExecNode(ctx.start.getCharPositionInLine(), mh); } private void checkHandle(MethodHandle mh, ParserRuleContext ctx) { @@ -127,7 +127,7 @@ class CompilingVisitor extends ExpressionBaseVisitor { MethodHandles.identity(Double.class) ); // now pass `result` into `guard` - MethodHandle result = evaluate(ctx).handle; + MethodHandle result = evaluate(ctx).handle(); return MethodHandles.collectArguments(guard, 0, result); } @@ -151,8 +151,8 @@ class CompilingVisitor extends ExpressionBaseVisitor { // easiest one of the bunch return MethodHandles.guardWithTest( evaluateBoolean(condition), - trueBranch == null ? NULL_DOUBLE : evaluate(trueBranch).handle, - falseBranch == null ? NULL_DOUBLE : evaluate(falseBranch).handle + trueBranch == null ? NULL_DOUBLE : evaluate(trueBranch).handle(), + falseBranch == null ? NULL_DOUBLE : evaluate(falseBranch).handle() ); } @@ -185,10 +185,10 @@ class CompilingVisitor extends ExpressionBaseVisitor { @Override public MethodHandle visitForStatement(ExpressionParser.ForStatementContext ctx) { return ExpressionHandles.forLoop( - evaluate(ctx.init).handle, + evaluate(ctx.init).handle(), evaluateBoolean(ctx.condition), evaluate(ctx.body), - evaluate(ctx.update).handle + evaluate(ctx.update).handle() ); } @@ -235,7 +235,7 @@ class CompilingVisitor extends ExpressionBaseVisitor { RETURN_STATEMENT_BASE, 0, // map the Double back to ExecutionData via the returnValue - evaluate(ctx.value).handle + evaluate(ctx.value).handle() ); } @@ -262,7 +262,7 @@ class CompilingVisitor extends ExpressionBaseVisitor { @Override public MethodHandle visitExpressionStatement(ExpressionParser.ExpressionStatementContext ctx) { - return evaluate(ctx.expression()).handle; + return evaluate(ctx.expression()).handle(); } @Override @@ -271,7 +271,7 @@ class CompilingVisitor extends ExpressionBaseVisitor { int opType = ctx.op.getType(); return ExpressionHandles.call(data -> { LocalSlot.Variable variable = ExpressionHandles.getVariable(data, target); - double value = variable.getValue(); + double value = variable.value(); double result = value; if (opType == INCREMENT) { value++; @@ -289,7 +289,7 @@ class CompilingVisitor extends ExpressionBaseVisitor { int opType = ctx.op.getType(); return ExpressionHandles.call(data -> { LocalSlot.Variable variable = ExpressionHandles.getVariable(data, target); - double value = variable.getValue(); + double value = variable.value(); if (opType == INCREMENT) { value++; } else { @@ -547,7 +547,7 @@ class CompilingVisitor extends ExpressionBaseVisitor { value = arg; } else { variable = ExpressionHandles.getVariable(data, target); - value = variable.getValue(); + value = variable.value(); switch (type) { case POWER_ASSIGN: value = Math.pow(value, arg); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExecNode.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExecNode.java index 6c53a13e5..86a944f03 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExecNode.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExecNode.java @@ -19,18 +19,7 @@ package com.sk89q.worldedit.internal.expression.invoke; -import org.antlr.v4.runtime.ParserRuleContext; - import java.lang.invoke.MethodHandle; -class ExecNode { - - final ParserRuleContext ctx; - final MethodHandle handle; - - ExecNode(ParserRuleContext ctx, MethodHandle handle) { - this.ctx = ctx; - this.handle = handle; - } - +record ExecNode(int positionInLine, MethodHandle handle) { } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExpressionHandles.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExpressionHandles.java index a2d0ad483..dab0be01b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExpressionHandles.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExpressionHandles.java @@ -200,7 +200,7 @@ class ExpressionHandles { static LocalSlot.Variable initVariable(ExecutionData data, Token nameToken) { String name = nameToken.getText(); - return data.getSlots().initVariable(name) + return data.slots().initVariable(name) .orElseThrow(() -> ExpressionHelper.evalException( nameToken, "Cannot overwrite non-variable '" + name + "'" )); @@ -218,7 +218,7 @@ class ExpressionHandles { static LocalSlot.Variable getVariable(ExecutionData data, Token nameToken) { String name = nameToken.getText(); - LocalSlot slot = data.getSlots().getSlot(name) + LocalSlot slot = data.slots().getSlot(name) .orElseThrow(varNotInitException(nameToken)); if (!(slot instanceof LocalSlot.Variable)) { throw ExpressionHelper.evalException( @@ -230,7 +230,7 @@ class ExpressionHandles { static double getSlotValue(ExecutionData data, Token nameToken) { String name = nameToken.getText(); - return data.getSlots().getSlotValue(name) + return data.slots().getSlotValue(name) .orElseThrow(varNotInitException(nameToken)); } @@ -302,11 +302,11 @@ class ExpressionHandles { standardInvoke(init, data); } while ((boolean) standardInvoke(condition, data)) { - checkIterations(iterations, body.ctx); + checkIterations(iterations, body.positionInLine()); data.checkDeadline(); iterations++; try { - result = (Double) standardInvoke(body.handle, data); + result = (Double) standardInvoke(body.handle(), data); } catch (BreakException ex) { if (!ex.doContinue) { break; @@ -331,11 +331,11 @@ class ExpressionHandles { Double result = null; int iterations = 0; do { - checkIterations(iterations, body.ctx); + checkIterations(iterations, body.positionInLine()); data.checkDeadline(); iterations++; try { - result = (Double) standardInvoke(body.handle, data); + result = (Double) standardInvoke(body.handle(), data); } catch (BreakException ex) { if (!ex.doContinue) { break; @@ -369,12 +369,12 @@ class ExpressionHandles { double last = (double) standardInvoke(getLast, data); LocalSlot.Variable variable = initVariable(data, counterToken); for (double i = first; i <= last; i++) { - checkIterations(iterations, body.ctx); + checkIterations(iterations, body.positionInLine()); data.checkDeadline(); iterations++; variable.setValue(i); try { - result = (Double) standardInvoke(body.handle, data); + result = (Double) standardInvoke(body.handle(), data); } catch (BreakException ex) { if (!ex.doContinue) { break; @@ -406,10 +406,10 @@ class ExpressionHandles { if (falling || entry.getDoubleKey() == value) { matched = true; try { - evaluated = (Double) standardInvoke(entry.getValue().handle, data); + evaluated = (Double) standardInvoke(entry.getValue().handle(), data); falling = true; } catch (BreakException brk) { - check(!brk.doContinue, entry.getValue().ctx, "Cannot continue in a switch"); + check(!brk.doContinue, entry.getValue().positionInLine(), "Cannot continue in a switch"); falling = false; break; } @@ -418,9 +418,9 @@ class ExpressionHandles { // This if is like the one in the loop, default's "case" is `!matched` & present if ((falling || !matched) && defaultCase != null) { try { - evaluated = (Double) standardInvoke(defaultCase.handle, data); + evaluated = (Double) standardInvoke(defaultCase.handle(), data); } catch (BreakException brk) { - check(!brk.doContinue, defaultCase.ctx, "Cannot continue in a switch"); + check(!brk.doContinue, defaultCase.positionInLine(), "Cannot continue in a switch"); } } return evaluated; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java index e892ba1f1..b31e62d7f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java @@ -19,6 +19,9 @@ package com.sk89q.worldedit.registry; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; + /** * Represents an objects that can be added to a registry and referenced by an id which is unique within its registry. */ @@ -28,7 +31,24 @@ public interface Keyed { * The id of this object in the registry. Must be unique, and lowercase. Certain registries (e.g Namespaced ones) may have additional restrictions. * * @return an id + * @deprecated Use {@link #id()} instead. */ - String getId(); + @Deprecated(forRemoval = true, since = "TODO") + default String getId() { + return id(); + } + + /** + * The id of this object in the registry. Must be unique and lowercase. Certain registries (e.g namespaced ones) + * may have additional restrictions. + * + * @return an id + * @since TODO + */ + @NonAbstractForCompatibility(delegateName = "getId", delegateParams = {}) + default String id() { + DeprecationUtil.checkDelegatingOverride(getClass()); + return getId(); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/Placement.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/Placement.java new file mode 100644 index 000000000..3171bc66e --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/Placement.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.session; + +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; + +//FAWE: not in use (yet) +public record Placement(PlacementType placementType, BlockVector3 offset) { + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + return placementType.getPlacementPosition(selector, actor).add(offset); + } + + public boolean canBeUsedBy(Actor actor) { + return placementType.canBeUsedBy(actor); + } + + public Component getInfo() { + if (offset.equals(BlockVector3.ZERO)) { + return TranslatableComponent.of(placementType.getTranslationKey()); + } else { + return TranslatableComponent.of( + placementType.getTranslationKeyWithOffset(), + TextComponent.of(offset.getX()), + TextComponent.of(offset.getY()), + TextComponent.of(offset.getZ()) + ); + } + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/PlacementType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/PlacementType.java new file mode 100644 index 000000000..90b6ff01e --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/PlacementType.java @@ -0,0 +1,119 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.session; + +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Locatable; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.RegionSelector; + +import static com.google.common.base.Preconditions.checkNotNull; + +//FAWE: not in use (yet) +public enum PlacementType { + WORLD("worldedit.toggleplace.world", "worldedit.toggleplace.world-offset") { + @Override + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + return BlockVector3.ZERO; + } + }, + + PLAYER("worldedit.toggleplace.player", "worldedit.toggleplace.player-offset") { + @Override + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + if (!canBeUsedBy(actor)) { + throw new IncompleteRegionException(); + } + return ((Locatable) actor).getBlockLocation().toVector().toBlockPoint(); + } + + @Override + public boolean canBeUsedBy(Actor actor) { + checkNotNull(actor); + return actor instanceof Locatable; + } + }, + + HERE(null, null) { + @Override + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + throw new IllegalStateException("PlacementType.HERE cannot be used. Use PLAYER or WORLD instead."); + } + + @Override + public boolean canBeUsedBy(Actor actor) { + return PLAYER.canBeUsedBy(actor); + } + + @Override + public String getTranslationKey() { + throw new IllegalStateException("PlacementType.HERE cannot be used. Use PLAYER or WORLD instead."); + } + + @Override + public String getTranslationKeyWithOffset() { + throw new IllegalStateException("PlacementType.HERE cannot be used. Use PLAYER or WORLD instead."); + } + }, + + POS1("worldedit.toggleplace.pos1", "worldedit.toggleplace.pos1-offset") { + @Override + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + return selector.getPrimaryPosition(); + } + }, + + MIN("worldedit.toggleplace.min", "worldedit.toggleplace.min-offset") { + @Override + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + return selector.getRegion().getMinimumPoint(); + } + }, + + MAX("worldedit.toggleplace.max", "worldedit.toggleplace.max-offset") { + @Override + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + return selector.getRegion().getMaximumPoint(); + } + }; + + private final String translationKey; + private final String translationKeyWithOffset; + + PlacementType(String translationKey, String translationKeyWithOffset) { + this.translationKey = translationKey; + this.translationKeyWithOffset = translationKeyWithOffset; + } + + public abstract BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException; + + public boolean canBeUsedBy(Actor actor) { + return true; + } + + public String getTranslationKey() { + return translationKey; + } + + public String getTranslationKeyWithOffset() { + return translationKeyWithOffset; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java index 2ea1d1d59..ff946e458 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java @@ -22,46 +22,38 @@ package com.sk89q.worldedit.util; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; -import java.util.Objects; - import static com.google.common.base.Preconditions.checkNotNull; /** * Represents a block located at some position. */ -public final class LocatedBlock { +public record LocatedBlock(BlockVector3 location, BaseBlock block) { - private final BlockVector3 location; - private final BaseBlock block; - - public LocatedBlock(BlockVector3 location, BaseBlock block) { - this.location = checkNotNull(location); - this.block = checkNotNull(block); + public LocatedBlock { + checkNotNull(location); + checkNotNull(block); } + /** + * Gets the location. + * + * @return The location + * @deprecated This class is now a record. Use {@link #location()} instead. + */ + @Deprecated(forRemoval = true, since = "TODO") public BlockVector3 getLocation() { - return location; + return this.location; } + /** + * Gets the block. + * + * @return The block + * @deprecated This class is now a record. Use {@link #block()} instead. + */ + @Deprecated(forRemoval = true, since = "TODO") public BaseBlock getBlock() { - return block; - } - - @Override - public int hashCode() { - return Objects.hash(location, block); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (this.getClass() != obj.getClass()) { - return false; - } - LocatedBlock lb = (LocatedBlock) obj; - return Objects.equals(location, lb.location) && Objects.equals(block, lb.block); + return this.block; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/DataReport.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/DataReport.java index 8a18f07b3..62e83a7b0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/DataReport.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/DataReport.java @@ -168,16 +168,7 @@ public class DataReport implements Report { } } - private static class Line { - - private final String key; - private final String value; - - public Line(String key, String value) { - this.key = key; - this.value = value; - } - + private record Line(String key, String value) { } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java index e8501da69..e7ec152a9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java @@ -28,21 +28,32 @@ import com.sk89q.worldedit.registry.NamespacedRegistry; /** * All the types of biomes in the game. */ -//FAWE start - RegistryItem +//FAWE start - RegistryItem + not a record (legacyId + internalId need mutability) public class BiomeType implements RegistryItem, Keyed, BiomePattern { //FAWE end public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("biome type", true); + //FAWE start private final String id; private int legacyId = -1; private int internalId; - //FAWE start public BiomeType(String id) { this.id = id; } + /** + * Gets the ID of this biome. + * + * @return The id + * @since TODO + */ + @Override + public String id() { + return this.id; + } + public int getLegacyId() { return legacyId; } @@ -60,13 +71,14 @@ public class BiomeType implements RegistryItem, Keyed, BiomePattern { public int getInternalId() { return internalId; } - //FAWE end /** * Gets the ID of this biome. * * @return The id + * @deprecated use {@link #id()} */ + @Deprecated(forRemoval = true, since = "TODO") @Override public String getId() { return this.id; @@ -74,20 +86,19 @@ public class BiomeType implements RegistryItem, Keyed, BiomePattern { @Override public String toString() { - return getId(); + return id(); } @Override public int hashCode() { - //FAWE start - internalId > hashCode - return this.internalId; // stop changing this - //FAWE end + return this.internalId; // stop changing this (ok) } @Override public boolean equals(Object obj) { return obj instanceof BiomeType && this.id.equals(((BiomeType) obj).id); } + //FAWE end @Override public BiomeType applyBiome(BlockVector3 position) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java index 5a530c8a6..1faf3bc4c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java @@ -23,13 +23,15 @@ import com.fastasyncworldedit.core.registry.RegistryItem; import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; -//FAWE start - implements RegistryItem +//FAWE start - implements RegistryItem, not a record (internalId needs mutability) public class EntityType implements RegistryItem, Keyed { //FAWE end public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("entity type", true); + //FAWE start private final String id; + private int internalId; public EntityType(String id) { // If it has no namespace, assume minecraft. @@ -39,14 +41,28 @@ public class EntityType implements RegistryItem, Keyed { this.id = id; } + /** + * Gets the id of this entity type. + * + * @return the id + * @since TODO + */ + public String id() { + return this.id; + } + + /** + * Gets the id of this entity type. + * + * @return the id + * @deprecated use {@link #id()} + */ + @Deprecated(forRemoval = true, since = "TODO") @Override public String getId() { return this.id; } - //FAWE start - private int internalId; - @Override public void setInternalId(int internalId) { this.internalId = internalId; @@ -64,14 +80,15 @@ public class EntityType implements RegistryItem, Keyed { * @return The name, or ID */ public String getName() { - return getId(); + return id(); } @Override public String toString() { - return getId(); + return id(); } + //FAWE start @Override public int hashCode() { return this.id.hashCode(); @@ -81,5 +98,6 @@ public class EntityType implements RegistryItem, Keyed { public boolean equals(Object obj) { return obj instanceof EntityType && this.id.equals(((EntityType) obj).id); } + //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java index d62d13b51..1642ed4e9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java @@ -24,15 +24,15 @@ import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; /** - * Minecraft now has a 'fluid' system. This is a - * stub class to represent what it may be in the future. + * Minecraft now has a 'fluid' system. This is a stub class to represent what it may be in the future. */ -//FAWE start - implements RegistryItem +//FAWE start - implements RegistryItem, not a record (internalId needs mutability) public class FluidType implements RegistryItem, Keyed { //FAWE end public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("fluid type"); + //FAWE start private final String id; public FluidType(String id) { @@ -43,7 +43,19 @@ public class FluidType implements RegistryItem, Keyed { * Gets the ID of this block. * * @return The id + * @since TODO */ + public String id() { + return this.id; + } + + /** + * Gets the ID of this block. + * + * @return The id + * @deprecated use {@link #id()} + */ + @Deprecated(forRemoval = true, since = "TODO") @Override public String getId() { return this.id; @@ -67,7 +79,7 @@ public class FluidType implements RegistryItem, Keyed { @Override public String toString() { - return getId(); + return id(); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameMode.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameMode.java index 312caa3b5..94b7b7cfe 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameMode.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameMode.java @@ -22,43 +22,21 @@ package com.sk89q.worldedit.world.gamemode; import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.Registry; -public class GameMode implements Keyed { +public record GameMode(String id) implements Keyed { public static final Registry REGISTRY = new Registry<>("game mode"); - private final String id; - - public GameMode(String id) { - this.id = id; - } - - @Override - public String getId() { - return this.id; - } - /** * Gets the name of this game mode, or the ID if the name cannot be found. * * @return The name, or ID */ public String getName() { - return getId(); + return id(); } @Override public String toString() { - return getId(); + return id(); } - - @Override - public int hashCode() { - return this.id.hashCode(); - } - - @Override - public boolean equals(Object obj) { - return obj instanceof GameMode && this.id.equals(((GameMode) obj).id); - } - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java index 19fe653fc..db63b53a4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java @@ -19,20 +19,53 @@ package com.sk89q.worldedit.world.registry; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; + public interface ItemMaterial { + /** + * Gets the the maximum quantity of this item that can be in a single stack. + * + * @return the maximum quantity + * @deprecated Use {@link #maxStackSize()} instead. + */ + @Deprecated(forRemoval = true, since = "TODO") + default int getMaxStackSize() { + return maxStackSize(); + } /** * Gets the the maximum quantity of this item that can be in a single stack. * * @return the maximum quantity + * @since TODO */ - int getMaxStackSize(); + @NonAbstractForCompatibility(delegateName = "getMaxStackSize", delegateParams = {}) + default int maxStackSize() { + DeprecationUtil.checkDelegatingOverride(getClass()); + return getMaxStackSize(); + } /** * Gets the the maximum damage this item can take before being broken. * * @return the maximum damage, or 0 if not applicable + * @deprecated Use {@link #maxDamage()} instead. */ - int getMaxDamage(); + @Deprecated(forRemoval = true, since = "TODO") + default int getMaxDamage() { + return maxDamage(); + } + /** + * Gets the the maximum damage this item can take before being broken. + * + * @return the maximum damage, or 0 if not applicable + * @since TODO + */ + @NonAbstractForCompatibility(delegateName = "getMaxDamage", delegateParams = {}) + default int maxDamage() { + DeprecationUtil.checkDelegatingOverride(getClass()); + return getMaxDamage(); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughItemMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughItemMaterial.java index 681add8cc..e5dac8a7f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughItemMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughItemMaterial.java @@ -34,13 +34,13 @@ public class PassthroughItemMaterial implements ItemMaterial { } @Override - public int getMaxStackSize() { - return itemMaterial.getMaxStackSize(); + public int maxStackSize() { + return itemMaterial.maxStackSize(); } @Override - public int getMaxDamage() { - return itemMaterial.getMaxDamage(); + public int maxDamage() { + return itemMaterial.maxDamage(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleItemMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleItemMaterial.java index 40ed03515..9e552e18a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleItemMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleItemMaterial.java @@ -19,24 +19,6 @@ package com.sk89q.worldedit.world.registry; -public class SimpleItemMaterial implements ItemMaterial { - - private final int maxStackSize; - private final int maxDamage; - - public SimpleItemMaterial(int maxStackSize, int maxDamage) { - this.maxStackSize = maxStackSize; - this.maxDamage = maxDamage; - } - - @Override - public int getMaxStackSize() { - return maxStackSize; - } - - @Override - public int getMaxDamage() { - return maxDamage; - } +public record SimpleItemMaterial(int maxStackSize, int maxDamage) implements ItemMaterial { } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherType.java index ea78ee112..4a7b3cd0c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherType.java @@ -22,43 +22,20 @@ package com.sk89q.worldedit.world.weather; import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.Registry; -public class WeatherType implements Keyed { - +public record WeatherType(String id) implements Keyed { public static final Registry REGISTRY = new Registry<>("weather type"); - private final String id; - - public WeatherType(String id) { - this.id = id; - } - - @Override - public String getId() { - return this.id; - } - /** * Gets the name of this weather, or the ID if the name cannot be found. * * @return The name, or ID */ public String getName() { - return getId(); + return id(); } @Override public String toString() { - return getId(); + return id(); } - - @Override - public int hashCode() { - return this.id.hashCode(); - } - - @Override - public boolean equals(Object obj) { - return obj instanceof WeatherType && this.id.equals(((WeatherType) obj).id); - } - } From a87124821f3922e6f13c809f3291d37197bcf989 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 01:53:35 +0000 Subject: [PATCH 272/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.2.14 (#2774) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 12c34eeca..bb46a654c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.2.12" +towny = "0.100.2.14" plotsquared = "7.3.8" # Third party From c6e297942f60709cd4ec57e75b26e3bc80bccf3f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 01:54:22 +0000 Subject: [PATCH 273/466] Update dependency paperweight-userdev to v1.20.6-R0.1-20240604.210637-112 (#2775) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts index 43bc53f15..a2b5aa66d 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/ - the().paperDevBundle("1.20.6-R0.1-20240602.222958-106") + the().paperDevBundle("1.20.6-R0.1-20240604.210637-112") compileOnly(libs.paperlib) } From 62297f9479db21ba62a71e31e14f3c29ca28c478 Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 10 Jun 2024 20:11:04 +0200 Subject: [PATCH 274/466] refactor: adjust chunk sending (#2770) - synchronise on the chunk GET object (when available) - kick it off to be run at some point on the main server thread --- .../PaperweightFaweWorldNativeAccess.java | 4 +- .../fawe/v1_19_R3/PaperweightGetBlocks.java | 6 +-- .../v1_19_R3/PaperweightPlatformAdapter.java | 41 +++++++++++-------- .../PaperweightStarlightRelighter.java | 2 +- .../PaperweightFaweWorldNativeAccess.java | 4 +- .../fawe/v1_20_R1/PaperweightGetBlocks.java | 6 +-- .../v1_20_R1/PaperweightPlatformAdapter.java | 37 +++++++++-------- .../PaperweightStarlightRelighter.java | 2 +- .../PaperweightFaweWorldNativeAccess.java | 4 +- .../fawe/v1_20_R2/PaperweightGetBlocks.java | 6 +-- .../v1_20_R2/PaperweightPlatformAdapter.java | 37 +++++++++-------- .../PaperweightStarlightRelighter.java | 2 +- .../PaperweightFaweWorldNativeAccess.java | 4 +- .../fawe/v1_20_R3/PaperweightGetBlocks.java | 9 ++-- .../v1_20_R3/PaperweightPlatformAdapter.java | 37 +++++++++-------- .../PaperweightStarlightRelighter.java | 2 +- .../PaperweightFaweWorldNativeAccess.java | 4 +- .../fawe/v1_20_R4/PaperweightGetBlocks.java | 6 +-- .../v1_20_R4/PaperweightPlatformAdapter.java | 37 +++++++++-------- .../PaperweightStarlightRelighter.java | 2 +- .../bukkit/adapter/BukkitGetBlocks.java | 2 +- .../bukkit/adapter/NMSAdapter.java | 2 +- 22 files changed, 139 insertions(+), 117 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweWorldNativeAccess.java index dbe0150a9..91fa70546 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweWorldNativeAccess.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweWorldNativeAccess.java @@ -246,7 +246,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess { + MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - true, - false // last false is to not bother with x-ray - ); + synchronized (chunk) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + true, + false // last false is to not bother with x-ray + ); + } } else { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - true - ); + synchronized (chunk) { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + true + ); + } } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java index 580bbf5a6..b1e0c5772 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java @@ -67,7 +67,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter { + MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - // last false is to not bother with x-ray - ); + synchronized (chunk) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); + } } else { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); + synchronized (chunk) { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); + } } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java index 30df91459..7de83af21 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java @@ -67,7 +67,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter { + MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - // last false is to not bother with x-ray - ); + synchronized (chunk) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); + } } else { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); + synchronized (chunk) { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); + } } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java index e869046da..addf03867 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java @@ -67,7 +67,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter biomeRegistry; private final IdMap> biomeHolderIdMap; private final ConcurrentHashMap copies = new ConcurrentHashMap<>(); - private final Object sendLock = new Object(); private LevelChunkSection[] sections; private LevelChunk levelChunk; private DataLayer[] blockLight; @@ -808,7 +807,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc nmsChunk.setUnsaved(true); // send to player if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { - this.send(finalMask, finalLightUpdate); + this.send(); } if (finalizer != null) { finalizer.run(); @@ -904,10 +903,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public void send(int mask, boolean lighting) { - synchronized (sendLock) { - PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); - } + public void send() { + PaperweightPlatformAdapter.sendChunk(this, serverLevel, chunkX, chunkZ); } /** diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java index 23de00ade..2f25bc6f1 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java @@ -26,6 +26,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.IdMap; import net.minecraft.core.Registry; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; @@ -332,7 +333,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } @SuppressWarnings("deprecation") - public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) { + public static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int chunkZ) { ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); if (chunkHolder == null) { return; @@ -353,24 +354,28 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { if (levelChunk == null) { return; } - TaskManager.taskManager().task(() -> { + MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - // last false is to not bother with x-ray - ); + synchronized (chunk) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); + } } else { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); + synchronized (chunk) { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); + } } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java index 49f02bf8d..d9109b4df 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java @@ -67,7 +67,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter { + MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - // last false is to not bother with x-ray - ); + synchronized (chunk) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); + } } else { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); + synchronized (chunk) { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); + } } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighter.java index 476978b57..ae09dcc58 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighter.java @@ -67,7 +67,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter Date: Wed, 12 Jun 2024 15:00:40 +0200 Subject: [PATCH 275/466] chore: address deprecations from new records (#2768) * Category should implement Keyed --- .../ext/fawe/v1_19_R3/PaperweightAdapter.java | 8 +-- .../fawe/v1_19_R3/PaperweightFaweAdapter.java | 4 +- .../ext/fawe/v1_20_R1/PaperweightAdapter.java | 8 +-- .../fawe/v1_20_R1/PaperweightFaweAdapter.java | 4 +- .../ext/fawe/v1_20_R2/PaperweightAdapter.java | 8 +-- .../fawe/v1_20_R2/PaperweightFaweAdapter.java | 4 +- .../ext.fawe/v1_20_R3/PaperweightAdapter.java | 8 +-- .../fawe/v1_20_R3/PaperweightFaweAdapter.java | 4 +- .../ext.fawe/v1_20_R4/PaperweightAdapter.java | 8 +-- .../fawe/v1_20_R4/PaperweightFaweAdapter.java | 4 +- .../bukkit/adapter/IBukkitAdapter.java | 12 ++--- .../worldedit/bukkit/BukkitBiomeRegistry.java | 2 +- .../sk89q/worldedit/bukkit/BukkitPlayer.java | 4 +- .../bukkit/BukkitServerInterface.java | 2 +- .../sk89q/worldedit/bukkit/BukkitWorld.java | 2 +- .../sk89q/worldedit/cli/CLIBlockRegistry.java | 2 +- .../com/sk89q/worldedit/cli/CLIPlatform.java | 2 +- .../cli/schematic/ClipboardWorld.java | 2 +- .../core/extent/DisallowedBlocksExtent.java | 4 +- .../core/extent/HistoryExtent.java | 4 +- .../clipboard/io/FastSchematicWriter.java | 4 +- .../io/schematic/MinecraftStructure.java | 4 +- .../processor/lighting/NMSRelighter.java | 22 ++++---- .../core/function/generator/CavesGen.java | 4 +- .../core/function/mask/ABlockMask.java | 2 +- .../core/function/mask/BlockMaskBuilder.java | 6 +-- .../function/pattern/TypeSwapPattern.java | 2 +- .../history/changeset/AbstractChangeSet.java | 2 +- .../core/util/MainUtil.java | 2 +- .../core/util/TextureUtil.java | 6 +-- .../sk89q/worldedit/LocalConfiguration.java | 4 +- .../com/sk89q/worldedit/LocalSession.java | 4 +- .../com/sk89q/worldedit/blocks/BaseItem.java | 2 +- .../worldedit/command/BiomeCommands.java | 4 +- .../worldedit/command/GeneralCommands.java | 4 +- .../worldedit/command/SelectionCommands.java | 4 +- .../command/argument/WorldConverter.java | 4 +- .../command/tool/BlockDataCyler.java | 2 +- .../factory/parser/DefaultBlockParser.java | 50 +++++++++---------- .../pattern/BlockCategoryPatternParser.java | 2 +- .../extension/platform/Platform.java | 2 +- .../worldedit/extent/clipboard/Clipboard.java | 2 +- .../clipboard/io/SpongeSchematicWriter.java | 4 +- .../FlowerPotCompatibilityHandler.java | 2 +- .../Pre13HangingCompatibilityHandler.java | 2 +- .../transform/BlockTransformExtent.java | 2 +- .../function/block/SnowSimulator.java | 4 +- .../changeset/BlockOptimizedHistory.java | 2 +- .../internal/cui/ServerCUIHandler.java | 2 +- .../sk89q/worldedit/registry/Category.java | 7 +-- .../util/PropertiesConfiguration.java | 4 +- .../com/sk89q/worldedit/world/NullWorld.java | 2 +- .../java/com/sk89q/worldedit/world/World.java | 2 +- .../worldedit/world/biome/BiomeTypes.java | 2 +- .../worldedit/world/block/BlockState.java | 2 +- .../world/block/BlockStateHolder.java | 4 +- .../worldedit/world/block/BlockType.java | 14 +++--- .../worldedit/world/block/BlockTypes.java | 4 +- .../worldedit/world/chunk/AnvilChunk13.java | 2 +- .../worldedit/world/chunk/AnvilChunk17.java | 2 +- .../worldedit/world/chunk/AnvilChunk18.java | 2 +- .../world/fluid/FluidCategories.java | 2 +- .../worldedit/world/fluid/FluidTypes.java | 2 +- .../worldedit/world/gamemode/GameModes.java | 2 +- .../sk89q/worldedit/world/item/ItemType.java | 6 +-- .../world/registry/BundledBlockRegistry.java | 8 +-- .../world/registry/BundledItemRegistry.java | 8 +-- .../world/registry/CategoryRegistry.java | 2 +- .../world/registry/NullBiomeRegistry.java | 2 +- .../worldedit/world/weather/WeatherTypes.java | 2 +- 70 files changed, 166 insertions(+), 167 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java index 6d1038677..fa027e567 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java @@ -283,11 +283,11 @@ public final class PaperweightAdapter implements BukkitImplAdapter { - if (itemStack.getType().getId().equalsIgnoreCase(WorldEdit.getInstance().getConfiguration().wandItem)) { + if (itemStack.getType().id().equalsIgnoreCase(WorldEdit.getInstance().getConfiguration().wandItem)) { inv.remove(newItem); } final ItemStack item = player.getInventory().getItemInMainHand(); @@ -267,7 +267,7 @@ public class BukkitPlayer extends AbstractPlayerActor { @Override public void setGameMode(GameMode gameMode) { - player.setGameMode(org.bukkit.GameMode.valueOf(gameMode.getId().toUpperCase(Locale.ROOT))); + player.setGameMode(org.bukkit.GameMode.valueOf(gameMode.id().toUpperCase(Locale.ROOT))); } @Override diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index 3bf09481e..01d84e8ef 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 @@ -230,7 +230,7 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser //FAWE start @Override - public String getId() { + public String id() { return "intellectualsites:bukkit"; } //FAWE end 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 b2fdeead9..66507c151 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 @@ -224,7 +224,7 @@ public class BukkitWorld extends AbstractWorld { //FAWE end @Override - public String getId() { + public String id() { return getWorld().getName().replace(" ", "_").toLowerCase(Locale.ROOT); } 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 index 1fdb97ae6..01ad15c1e 100644 --- a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIBlockRegistry.java +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIBlockRegistry.java @@ -68,7 +68,7 @@ public class CLIBlockRegistry extends BundledBlockRegistry { @Override public Map> getProperties(BlockType blockType) { Map properties = - CLIWorldEdit.inst.getFileRegistries().getDataFile().blocks.get(blockType.getId()).properties; + CLIWorldEdit.inst.getFileRegistries().getDataFile().blocks.get(blockType.id()).properties; Maps.EntryTransformer> entryTransform = (key, value) -> createProperty(value.type, key, value.values); return ImmutableMap.copyOf(Maps.transformEntries(properties, entryTransform)); 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 index e9a397b73..4895a2922 100644 --- a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIPlatform.java +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIPlatform.java @@ -115,7 +115,7 @@ class CLIPlatform extends AbstractPlatform { @Override public World matchWorld(World world) { return this.worlds.stream() - .filter(w -> w.getId().equals(world.getId())) + .filter(w -> w.id().equals(world.id())) .findAny() .orElse(null); } 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 index a8190234c..e0b4c64f2 100644 --- 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 @@ -85,7 +85,7 @@ public class ClipboardWorld extends AbstractWorld implements Clipboard, CLIWorld //FAWE end @Override - public String getId() { + public String id() { return getName().replace(" ", "_").toLowerCase(Locale.ROOT); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/DisallowedBlocksExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/DisallowedBlocksExtent.java index f1c523ce3..11f15131f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/DisallowedBlocksExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/DisallowedBlocksExtent.java @@ -101,7 +101,7 @@ public class DisallowedBlocksExtent extends AbstractDelegateExtent implements IB @SuppressWarnings("unchecked") private > B checkBlock(B block) { if (blockedBlocks != null) { - if (blockedBlocks.contains(block.getBlockType().getId())) { + if (blockedBlocks.contains(block.getBlockType().id())) { return (B) (block instanceof BlockState ? RESERVED : RESERVED.toBaseBlock()); // set to reserved/empty } } @@ -140,7 +140,7 @@ public class DisallowedBlocksExtent extends AbstractDelegateExtent implements IB } BlockState state = BlockTypesCache.states[block]; if (blockedBlocks != null) { - if (blockedBlocks.contains(state.getBlockType().getId())) { + if (blockedBlocks.contains(state.getBlockType().id())) { blocks[i] = BlockTypesCache.ReservedIDs.__RESERVED__; continue; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java index d85594215..daad170da 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java @@ -110,7 +110,7 @@ public class HistoryExtent extends AbstractDelegateExtent { @Override public boolean setBiome(BlockVector3 position, BiomeType newBiome) { BiomeType oldBiome = this.getBiome(position); - if (!oldBiome.getId().equals(newBiome.getId())) { + if (!oldBiome.id().equals(newBiome.id())) { this.changeSet.addBiomeChange(position.x(), position.y(), position.z(), oldBiome, newBiome); return getExtent().setBiome(position, newBiome); } else { @@ -121,7 +121,7 @@ public class HistoryExtent extends AbstractDelegateExtent { @Override public boolean setBiome(int x, int y, int z, BiomeType newBiome) { BiomeType oldBiome = this.getBiome(mutable.setComponents(x, y, z)); - if (!oldBiome.getId().equals(newBiome.getId())) { + if (!oldBiome.id().equals(newBiome.id())) { this.changeSet.addBiomeChange(x, y, z, oldBiome, newBiome); return getExtent().setBiome(x, y, z, newBiome); } else { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java index 5218b1c1e..65a4a0e86 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java @@ -237,7 +237,7 @@ public class FastSchematicWriter implements ClipboardWriter { if (!brokenEntities) { loc = loc.setPosition(loc.add(min.toVector3())); } - values.put("Id", new StringTag(state.getType().getId())); + values.put("Id", new StringTag(state.getType().id())); values.put("Pos", writeVector(loc)); values.put("Rotation", writeRotation(entity.getLocation())); @@ -297,7 +297,7 @@ public class FastSchematicWriter implements ClipboardWriter { for (int i = 0; i < paletteList.size(); i++) { int ordinal = paletteList.get(i); BiomeType state = BiomeTypes.get(ordinal); - out12.writeNamedTag(state.getId(), i); + out12.writeNamedTag(state.id(), i); } }); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java index d52d74b5a..0779418df 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java @@ -183,7 +183,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { indexes.put(combined, (Integer) palette.size()); HashMap paletteEntry = new HashMap<>(); - paletteEntry.put("Name", type.getId()); + paletteEntry.put("Name", type.id()); if (block.getInternalId() != type.getInternalId()) { Map properties = null; for (AbstractProperty property : (List>) type.getProperties()) { @@ -239,7 +239,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { Map nbtMap = nbt.getValue(); // Replace rotation data nbtMap.put("Rotation", writeRotation(entity.getLocation())); - nbtMap.put("id", new StringTag(state.getType().getId())); + nbtMap.put("id", new StringTag(state.getType().id())); Map entityMap = FaweCache.INSTANCE.asMap("pos", pos, "blockPos", blockPos, "nbt", nbt); entities.add(entityMap); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/NMSRelighter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/NMSRelighter.java index dbe717e49..2ad473130 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/NMSRelighter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/NMSRelighter.java @@ -346,7 +346,7 @@ public class NMSRelighter implements Relighter { } int lightLevel = iChunk.getEmittedLight(node.x() & 15, node.y(), node.z() & 15); BlockState state = this.queue.getBlock(node.x(), node.y(), node.z()); - String id = state.getBlockType().getId().toLowerCase(Locale.ROOT); + String id = state.getBlockType().id().toLowerCase(Locale.ROOT); if (lightLevel <= 1) { continue; } @@ -396,7 +396,7 @@ public class NMSRelighter implements Relighter { if (!(checkStairEast(state) && isStairOrTrueTop(state, top) && isSlabOrTrueValue(state, top ? "top" : "bottom"))) { break east; } - if (!state.getBlockType().getId().toLowerCase(Locale.ROOT).contains("stair")) { + if (!state.getBlockType().id().toLowerCase(Locale.ROOT).contains("stair")) { this.computeSpreadBlockLight(x + 1, y, z, currentLight, queue, visited); break east; } @@ -449,7 +449,7 @@ public class NMSRelighter implements Relighter { if (!(checkStairWest(state) && isStairOrTrueTop(state, top) && isSlabOrTrueValue(state, top ? "top" : "bottom"))) { break west; } - if (!state.getBlockType().getId().toLowerCase(Locale.ROOT).contains("stair")) { + if (!state.getBlockType().id().toLowerCase(Locale.ROOT).contains("stair")) { this.computeSpreadBlockLight(x - 1, y, z, currentLight, queue, visited); break west; } @@ -502,7 +502,7 @@ public class NMSRelighter implements Relighter { if (!(checkStairSouth(state) && isStairOrTrueTop(state, top) && isSlabOrTrueValue(state, top ? "top" : "bottom"))) { break south; } - if (!state.getBlockType().getId().toLowerCase(Locale.ROOT).contains("stair")) { + if (!state.getBlockType().id().toLowerCase(Locale.ROOT).contains("stair")) { this.computeSpreadBlockLight(x, y, z + 1, currentLight, queue, visited); break south; } @@ -555,7 +555,7 @@ public class NMSRelighter implements Relighter { if (!(checkStairNorth(state) && isStairOrTrueTop(state, top) && isSlabOrTrueValue(state, top ? "top" : "bottom"))) { break north; } - if (!state.getBlockType().getId().toLowerCase(Locale.ROOT).contains("stair")) { + if (!state.getBlockType().id().toLowerCase(Locale.ROOT).contains("stair")) { this.computeSpreadBlockLight(x, y, z - 1, currentLight, queue, visited); break north; } @@ -707,7 +707,7 @@ public class NMSRelighter implements Relighter { } private boolean checkStairNorth(BlockState state) { - if (!state.getBlockType().getId().toLowerCase(Locale.ROOT).contains("stair")) { + if (!state.getBlockType().id().toLowerCase(Locale.ROOT).contains("stair")) { return true; } Direction direction = getStairDir(state); @@ -725,7 +725,7 @@ public class NMSRelighter implements Relighter { } private boolean checkStairSouth(BlockState state) { - if (!state.getBlockType().getId().toLowerCase(Locale.ROOT).contains("stair")) { + if (!state.getBlockType().id().toLowerCase(Locale.ROOT).contains("stair")) { return true; } Direction direction = getStairDir(state); @@ -743,7 +743,7 @@ public class NMSRelighter implements Relighter { } private boolean checkStairEast(BlockState state) { - if (!state.getBlockType().getId().toLowerCase(Locale.ROOT).contains("stair")) { + if (!state.getBlockType().id().toLowerCase(Locale.ROOT).contains("stair")) { return true; } Direction direction = getStairDir(state); @@ -761,7 +761,7 @@ public class NMSRelighter implements Relighter { } private boolean checkStairWest(BlockState state) { - if (!state.getBlockType().getId().toLowerCase(Locale.ROOT).contains("stair")) { + if (!state.getBlockType().id().toLowerCase(Locale.ROOT).contains("stair")) { return true; } Direction direction = getStairDir(state); @@ -787,11 +787,11 @@ public class NMSRelighter implements Relighter { } private boolean isStairOrTrueTop(BlockState state, boolean top) { - return !state.getBlockType().getId().contains("stair") || state.getState(stairHalf).equals("top") == top; + return !state.getBlockType().id().contains("stair") || state.getState(stairHalf).equals("top") == top; } private boolean isSlabOrTrueValue(BlockState state, String value) { - return !state.getBlockType().getId().contains("slab") || state.getState(slabHalf).equals(value); + return !state.getBlockType().id().contains("slab") || state.getState(slabHalf).equals(value); } private void computeRemoveBlockLight( diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/CavesGen.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/CavesGen.java index b9a403f27..7e4b61514 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/CavesGen.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/CavesGen.java @@ -236,7 +236,7 @@ public class CavesGen extends GenBase { BlockState material = chunk.getBlock(bx + local_x, local_y, bz + local_z); BlockState materialAbove = chunk.getBlock(bx + local_x, local_y + 1, bz + local_z); BlockType blockType = material.getBlockType(); - switch (blockType.getId()) { + switch (blockType.id()) { case "minecraft:mycelium", "minecraft:grass_block" -> grassFound = true; } if (this.isSuitableBlock(material, materialAbove)) { @@ -277,7 +277,7 @@ public class CavesGen extends GenBase { } protected boolean isSuitableBlock(BlockStateHolder material, BlockStateHolder materialAbove) { - return switch (material.getBlockType().getId()) { + return switch (material.getBlockType().id()) { case "minecraft:air", "minecraft:cave_air", "minecraft:void_air", "minecraft:water", "minecraft:lava", "minecraft:bedrock" -> false; default -> true; }; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ABlockMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ABlockMask.java index 1f0b88bfa..7fdebdded 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ABlockMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ABlockMask.java @@ -40,7 +40,7 @@ public abstract class ABlockMask extends AbstractExtentMask { List all = type.getAllStates(); hasAll = all.stream().map(this::test).reduce(true, (a, b) -> a && b); if (hasAll) { - strings.add(type.getId()); + strings.add(type.id()); } else { for (BlockState state : all) { if (test(state)) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java index 2471ff262..baef7f767 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java @@ -183,7 +183,7 @@ public class BlockMaskBuilder { builders = new ArrayList<>(); Pattern pattern = Pattern.compile("(minecraft:)?" + regex); for (BlockType type : BlockTypesCache.values) { - if (pattern.matcher(type.getId()).find()) { + if (pattern.matcher(type.id()).find()) { blockTypeList.add(type); builders.add(new FuzzyStateAllowingBuilder(type)); add(type); @@ -284,7 +284,7 @@ public class BlockMaskBuilder { } else { boolean success = false; for (BlockType myType : BlockTypesCache.values) { - if (myType.getId().matches("(minecraft:)?" + input)) { + if (myType.id().matches("(minecraft:)?" + input)) { add(myType); success = true; } @@ -571,7 +571,7 @@ public class BlockMaskBuilder { throw new IllegalArgumentException(String.format( "Property %s cannot be applied to block type %s", property.getName(), - type.getId() + type.id() )); } masked.computeIfAbsent(property, k -> new ArrayList<>()).add(index); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/TypeSwapPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/TypeSwapPattern.java index efc122b5d..d222833a7 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/TypeSwapPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/TypeSwapPattern.java @@ -79,7 +79,7 @@ public class TypeSwapPattern extends AbstractExtentPattern { } private BlockState getNewBlock(BlockState existing) { - String oldId = existing.getBlockType().getId(); + String oldId = existing.getBlockType().id(); String newId = oldId; if (inputPattern != null) { newId = inputPattern.matcher(oldId).replaceAll(outputString); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java index e5820fd44..08165577f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java @@ -297,7 +297,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { public void add(BlockChange change) { try { BlockVector3 loc = change.getPosition(); - BaseBlock from = change.getPrevious(); + BaseBlock from = change.previous(); BaseBlock to = change.getCurrent(); add(loc, from, to); } catch (Exception e) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java index 117ab8fab..7d7d5d642 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java @@ -444,7 +444,7 @@ public class MainUtil { @Nonnull public static CompoundTag setEntityInfo(@Nonnull CompoundTag tag, @Nonnull Entity entity) { Map map = new HashMap<>(tag.getValue()); - map.put("Id", new StringTag(entity.getState().getType().getId())); + map.put("Id", new StringTag(entity.getState().getType().id())); ListTag pos = (ListTag) map.get("Pos"); if (pos != null) { Location loc = entity.getLocation(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TextureUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TextureUtil.java index f6f896f56..7c4e7137b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TextureUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TextureUtil.java @@ -929,10 +929,10 @@ public class TextureUtil implements TextureHolder { }.getType(); for (BlockType blockType : BlockTypesCache.values) { - if (!blockType.getMaterial().isFullCube() || blockType.getId().toLowerCase().contains("shulker")) { + if (!blockType.getMaterial().isFullCube() || blockType.id().toLowerCase().contains("shulker")) { continue; } - switch (blockType.getId().toLowerCase(Locale.ROOT)) { + switch (blockType.id().toLowerCase(Locale.ROOT)) { case "slime_block": case "honey_block": case "mob_spawner": @@ -940,7 +940,7 @@ public class TextureUtil implements TextureHolder { continue; } int combined = blockType.getInternalId(); - String id = blockType.getId(); + String id = blockType.id(); String[] split = id.split(":", 2); String name = split.length == 1 ? id : split[1]; String nameSpace = split.length == 1 ? "" : split[0]; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java index 7e2ba4549..1301c5bb3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java @@ -196,7 +196,7 @@ public abstract class LocalConfiguration { BlockTypes.BEDROCK FAWE end*/ ); - return blockTypes.stream().filter(Objects::nonNull).map(BlockType::getId).toArray(String[]::new); + return blockTypes.stream().filter(Objects::nonNull).map(BlockType::id).toArray(String[]::new); } /** @@ -277,7 +277,7 @@ public abstract class LocalConfiguration { id = Integer.parseInt(splitter[0]); data = Byte.parseByte(splitter[1]); } - item = LegacyMapper.getInstance().getItemFromLegacy(id, data).getId(); + item = LegacyMapper.getInstance().getItemFromLegacy(id, data).id(); } catch (Throwable ignored) { } 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 5df95414b..7642f3d60 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -1899,7 +1899,7 @@ public class LocalSession implements TextureHolder { */ @Deprecated public String getWandItem() { - return wandItem.getType().getId(); + return wandItem.getType().id(); } /** @@ -1910,7 +1910,7 @@ public class LocalSession implements TextureHolder { */ @Deprecated public String getNavWandItem() { - return navWandItem.getType().getId(); + return navWandItem.getType().id(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java index ac8236297..fe2e1a635 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java @@ -129,7 +129,7 @@ public class BaseItem implements NbtValued { } } - return getType().getId() + nbtString; + return getType().id() + nbtString; } //FAWE end } 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 0b2bd576d..a60968da1 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 @@ -98,7 +98,7 @@ public class BiomeCommands { PaginationBox paginationBox = PaginationBox.fromComponents("Available Biomes", "/biomelist -p %page%", BiomeType.REGISTRY.values().stream() .map(biomeType -> TextComponent.builder() - .append(biomeType.getId()) + .append(biomeType.id()) .append(" (") .append(biomeRegistry.getRichName(biomeType)) .append(")") @@ -166,7 +166,7 @@ public class BiomeCommands { List components = biomes.stream().map(biome -> biomeRegistry.getRichName(biome).hoverEvent( - HoverEvent.showText(TextComponent.of(biome.getId())) + HoverEvent.showText(TextComponent.of(biome.id())) ) ).collect(Collectors.toList()); actor.print(Caption.of(messageKey, TextUtils.join(components, TextComponent.of(", ")))); 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 0cf5b1a78..3b271a1ec 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 @@ -349,7 +349,7 @@ public class GeneralCommands { if (world == null) { actor.print(Caption.of("worldedit.world.remove")); } else { - actor.print(Caption.of("worldedit.world.set", TextComponent.of(world.getId()))); + actor.print(Caption.of("worldedit.world.set", TextComponent.of(world.id()))); } } @@ -641,7 +641,7 @@ public class GeneralCommands { if (itemsOnly && searchType.hasBlockType()) { continue; } - final String id = searchType.getId(); + final String id = searchType.id(); if (id.contains(idMatch)) { Component name = searchType.getRichName(); results.put(id, TextComponent.builder() 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 d000fcef7..ddca046ff 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 @@ -79,8 +79,6 @@ import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.item.ItemType; -import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.storage.ChunkStore; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; @@ -841,7 +839,7 @@ public class SelectionCommands { toolTip = TextComponent.of(state.getAsString()); blockName = blockName.append(TextComponent.of("*")); } else { - toolTip = TextComponent.of(blockType.getId()); + toolTip = TextComponent.of(blockType.id()); } blockName = blockName.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, toolTip)); line.append(blockName); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/WorldConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/WorldConverter.java index fd043d440..54492497a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/WorldConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/WorldConverter.java @@ -65,7 +65,7 @@ public class WorldConverter implements ArgumentConverter { @Override public List getSuggestions(String input, InjectedValueAccess context) { return getWorlds() - .map(World::getId) + .map(World::id) .filter(world -> world.startsWith(input)) .collect(Collectors.toList()); } @@ -73,7 +73,7 @@ public class WorldConverter implements ArgumentConverter { @Override public ConversionResult convert(String s, InjectedValueAccess injectedValueAccess) { World result = getWorlds() - .filter(world -> world.getId().equals(s)) + .filter(world -> world.id().equals(s)) .findAny().orElse(null); return result == null ? FailedConversion.from(new IllegalArgumentException( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java index b9a2ee888..2d35b2226 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java @@ -66,7 +66,7 @@ public class BlockDataCyler implements DoubleActionBlockTool { if (!config.allowedDataCycleBlocks.isEmpty() && !player.hasPermission("worldedit.override.data-cycler") - && !config.allowedDataCycleBlocks.contains(block.getBlockType().getId())) { + && !config.allowedDataCycleBlocks.contains(block.getBlockType().id())) { player.print(Caption.of("worldedit.tool.data-cycler.block-not-permitted")); return true; } 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 969216896..03cfb51e3 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 @@ -135,42 +135,42 @@ public class DefaultBlockParser extends InputParser { private String woolMapper(String string) { switch (string.toLowerCase(Locale.ROOT)) { case "white": - return BlockTypes.WHITE_WOOL.getId(); + return BlockTypes.WHITE_WOOL.id(); case "black": - return BlockTypes.BLACK_WOOL.getId(); + return BlockTypes.BLACK_WOOL.id(); case "blue": - return BlockTypes.BLUE_WOOL.getId(); + return BlockTypes.BLUE_WOOL.id(); case "brown": - return BlockTypes.BROWN_WOOL.getId(); + return BlockTypes.BROWN_WOOL.id(); case "cyan": - return BlockTypes.CYAN_WOOL.getId(); + return BlockTypes.CYAN_WOOL.id(); case "gray": case "grey": - return BlockTypes.GRAY_WOOL.getId(); + return BlockTypes.GRAY_WOOL.id(); case "green": - return BlockTypes.GREEN_WOOL.getId(); + return BlockTypes.GREEN_WOOL.id(); case "light_blue": case "lightblue": - return BlockTypes.LIGHT_BLUE_WOOL.getId(); + return BlockTypes.LIGHT_BLUE_WOOL.id(); case "light_gray": case "light_grey": case "lightgray": case "lightgrey": - return BlockTypes.LIGHT_GRAY_WOOL.getId(); + return BlockTypes.LIGHT_GRAY_WOOL.id(); case "lime": - return BlockTypes.LIME_WOOL.getId(); + return BlockTypes.LIME_WOOL.id(); case "magenta": - return BlockTypes.MAGENTA_WOOL.getId(); + return BlockTypes.MAGENTA_WOOL.id(); case "orange": - return BlockTypes.ORANGE_WOOL.getId(); + return BlockTypes.ORANGE_WOOL.id(); case "pink": - return BlockTypes.PINK_WOOL.getId(); + return BlockTypes.PINK_WOOL.id(); case "purple": - return BlockTypes.PURPLE_WOOL.getId(); + return BlockTypes.PURPLE_WOOL.id(); case "yellow": - return BlockTypes.YELLOW_WOOL.getId(); + return BlockTypes.YELLOW_WOOL.id(); case "red": - return BlockTypes.RED_WOOL.getId(); + return BlockTypes.RED_WOOL.id(); default: return string; } @@ -194,7 +194,7 @@ public class DefaultBlockParser extends InputParser { if (input.indexOf('[') == -1 && input.indexOf(']') == -1) { continue; } - if (!type.getId().equalsIgnoreCase(input.substring(0, input.indexOf('[')))) { + if (!type.id().equalsIgnoreCase(input.substring(0, input.indexOf('[')))) { continue; } String[] properties = input.substring(input.indexOf('[') + 1, input.indexOf(']')).split(","); @@ -249,10 +249,10 @@ public class DefaultBlockParser extends InputParser { throw new NoMatchException(Caption.of( "worldedit.error.parser.unknown-property", TextComponent.of(parts[0]), - TextComponent.of(type.getId()) + TextComponent.of(type.id()) )); } else { - WorldEdit.logger.debug("Unknown property " + parts[0] + " for block " + type.getId()); + WorldEdit.logger.debug("Unknown property " + parts[0] + " for block " + type.id()); } return Maps.newHashMap(); } @@ -516,20 +516,20 @@ public class DefaultBlockParser extends InputParser { //FAWE start - per-limit disallowed blocks if (actor != null) { if (!actor.hasPermission("worldedit.anyblock") - && worldEdit.getConfiguration().disallowedBlocks.contains(blockType.getId().toLowerCase(Locale.ROOT))) { + && worldEdit.getConfiguration().disallowedBlocks.contains(blockType.id().toLowerCase(Locale.ROOT))) { throw new DisallowedUsageException(Caption.of( "worldedit.error.disallowed-block", - TextComponent.of(blockType.getId()) + TextComponent.of(blockType.id()) )); } FaweLimit limit = actor.getLimit(); if (!limit.isUnlimited()) { // No need to account for blocked states/properties as it will simply return false in the equality check // during contains. - if (limit.DISALLOWED_BLOCKS.contains(blockType.getId().toLowerCase(Locale.ROOT))) { + if (limit.DISALLOWED_BLOCKS.contains(blockType.id().toLowerCase(Locale.ROOT))) { throw new DisallowedUsageException(Caption.of( "fawe.error.limit.disallowed-block", - TextComponent.of(blockType.getId()) + TextComponent.of(blockType.id()) )); } } @@ -559,14 +559,14 @@ public class DefaultBlockParser extends InputParser { if (ent == null) { throw new NoMatchException(Caption.of("worldedit.error.unknown-entity", TextComponent.of(mobName))); } - mobName = ent.getId(); + mobName = ent.id(); if (!worldEdit.getPlatformManager().queryCapability(Capability.USER_COMMANDS).isValidMobType(mobName)) { throw new NoMatchException(Caption.of("worldedit.error.unknown-mob", TextComponent.of(mobName))); } return validate(context, new MobSpawnerBlock(state, mobName)); } else { //noinspection ConstantConditions - return validate(context, new MobSpawnerBlock(state, EntityTypes.PIG.getId())); + return validate(context, new MobSpawnerBlock(state, EntityTypes.PIG.id())); } } else if (blockType == BlockTypes.PLAYER_HEAD || blockType == BlockTypes.PLAYER_WALL_HEAD) { // allow setting type/player/rotation diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java index 36d83eb37..089f2d861 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java @@ -71,7 +71,7 @@ public class BlockCategoryPatternParser extends InputParser implements Set blocks = category.getAll(); if (blocks.isEmpty()) { - throw new InputParseException(Caption.of("worldedit.error.empty-tag", TextComponent.of(category.getId()))); + throw new InputParseException(Caption.of("worldedit.error.empty-tag", TextComponent.of(category.id()))); } if (anyState) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java index f20f3ce9b..472dce93c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java @@ -233,7 +233,7 @@ public interface Platform extends Keyed { */ @NonAbstractForCompatibility(delegateName = "getPlatformName", delegateParams = {}) @Override - default String getId() { + default String id() { return "legacy:" + getPlatformName().toLowerCase(Locale.ROOT).replaceAll("[^a-z_.-]", "_"); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java index 4cd2ead97..cac9f4a7b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java @@ -423,7 +423,7 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl if (pasteEntities) { for (Entity entity : this.getEntities()) { // skip players on pasting schematic - if (entity.getState() != null && entity.getState().getType().getId() + if (entity.getState() != null && entity.getState().getType().id() .equals("minecraft:player")) { continue; } 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 24860dd3c..dc313b259 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 @@ -223,7 +223,7 @@ public class SpongeSchematicWriter implements ClipboardWriter { BlockVector3 pt = BlockVector3.at(x0, min.y(), z0); BiomeType biome = clipboard.getBiome(pt); - String biomeKey = biome.getId(); + String biomeKey = biome.id(); int biomeId; if (palette.containsKey(biomeKey)) { biomeId = palette.get(biomeKey); @@ -262,7 +262,7 @@ public class SpongeSchematicWriter implements ClipboardWriter { values.putAll(rawData.getValue()); } values.remove("id"); - values.put("Id", new StringTag(state.getType().getId())); + values.put("Id", new StringTag(state.getType().id())); final Location location = e.getLocation(); values.put("Pos", writeVector(location.toVector())); values.put("Rotation", writeRotation(location)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java index 974000762..95d2fb091 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java @@ -84,7 +84,7 @@ public class FlowerPotCompatibilityHandler implements NBTCompatibilityHandler { } else { BlockState plantedWithData = LegacyMapper.getInstance().getBlockFromLegacy(newId, data); if (plantedWithData != null) { - plantedName = plantedWithData.getBlockType().getId().substring(10); // remove "minecraft:" + plantedName = plantedWithData.getBlockType().id().substring(10); // remove "minecraft:" } } if (plantedName != null) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java index 25457042c..346f5f29e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java @@ -29,7 +29,7 @@ public class Pre13HangingCompatibilityHandler implements EntityNBTCompatibilityH @Override public boolean isAffectedEntity(EntityType type, CompoundTag tag) { - if (!type.getId().startsWith("minecraft:")) { + if (!type.id().startsWith("minecraft:")) { return false; } boolean hasLegacyDirection = tag.containsKey("Dir") || tag.containsKey("Direction"); 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 d9effa512..5f434cf9b 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 @@ -441,7 +441,7 @@ public class BlockTransformExtent extends ResettableExtent { if (Settings.settings().ENABLED_COMPONENTS.DEBUG) { LOGGER.warn(String.format( "Index outside direction array length found for block:{%s} property:{%s}", - state.getBlockType().getId(), + state.getBlockType().id(), property.getName() )); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/SnowSimulator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/SnowSimulator.java index 4027220b2..962fb3c7d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/SnowSimulator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/SnowSimulator.java @@ -116,7 +116,7 @@ public class SnowSimulator implements LayerFunction { if (!above.getBlockType().getMaterial().isAir() && (!stack || above.getBlockType() != BlockTypes.SNOW)) { return false; //FAWE start - } else if (!block.getBlockType().getId().toLowerCase(Locale.ROOT).contains("ice") && this.extent.getEmittedLight( + } else if (!block.getBlockType().id().toLowerCase(Locale.ROOT).contains("ice") && this.extent.getEmittedLight( abovePosition) > 10) { return false; } else if (!block.getBlockType().getMaterial().isFullCube()) { @@ -132,7 +132,7 @@ public class SnowSimulator implements LayerFunction { return false; } //FAWE end - } else if (!block.getBlockType().getId().toLowerCase(Locale.ROOT).contains("ice") && block + } else if (!block.getBlockType().id().toLowerCase(Locale.ROOT).contains("ice") && block .getBlockType() .getMaterial() .isTranslucent()) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java index 2019e3022..f358ebfae 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java @@ -56,7 +56,7 @@ public class BlockOptimizedHistory extends ArrayListHistory { BlockChange blockChange = (BlockChange) change; BlockVector3 position = blockChange.getPosition(); if (!previous.containsLocation(position)) { - previous.add(position, blockChange.getPrevious()); + previous.add(position, blockChange.previous()); } current.add(position, blockChange.getCurrent()); } else { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java index 8cc91f969..c30f6fa4d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java @@ -165,7 +165,7 @@ public class ServerCUIHandler { structureTag.putString("mode", "SAVE"); structureTag.putByte("ignoreEntities", (byte) 1); structureTag.putByte("showboundingbox", (byte) 1); - structureTag.putString("id", BlockTypes.STRUCTURE_BLOCK.getId()); + structureTag.putString("id", BlockTypes.STRUCTURE_BLOCK.id()); return BlockTypes.STRUCTURE_BLOCK.getDefaultState().toBaseBlock(structureTag.build()); //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Category.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Category.java index fc8a5e895..92a859652 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Category.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Category.java @@ -25,7 +25,7 @@ import java.util.HashSet; import java.util.Set; //FAWE start - implements RegistryItem -public abstract class Category implements RegistryItem { +public abstract class Category implements RegistryItem, Keyed { //FAWE end private final Set set = new HashSet<>(); @@ -36,7 +36,8 @@ public abstract class Category implements RegistryItem { this.id = id; } - public final String getId() { + @Override + public final String id() { return this.id; } @@ -81,7 +82,7 @@ public abstract class Category implements RegistryItem { @Override public String toString() { - return getId(); + return id(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java index 7bec7c2f5..7a52770e3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java @@ -114,7 +114,7 @@ public class PropertiesConfiguration extends LocalConfiguration { registerHelp = getBool("register-help", registerHelp); wandItem = getString("wand-item", wandItem); try { - wandItem = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(wandItem)).getId(); + wandItem = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(wandItem)).id(); } catch (Throwable ignored) { } superPickaxeDrop = getBool("super-pickaxe-drop-items", superPickaxeDrop); @@ -124,7 +124,7 @@ public class PropertiesConfiguration extends LocalConfiguration { useInventoryCreativeOverride = getBool("use-inventory-creative-override", useInventoryCreativeOverride); navigationWand = getString("nav-wand-item", navigationWand); try { - navigationWand = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(navigationWand)).getId(); + navigationWand = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(navigationWand)).id(); } catch (Throwable ignored) { } navigationWandMaxDistance = getInt("nav-wand-distance", navigationWandMaxDistance); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java index ccf8d8535..0e962d746 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -78,7 +78,7 @@ public class NullWorld extends AbstractWorld { //FAWE end @Override - public String getId() { + public String id() { return "null"; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java index 79822a934..553792599 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java @@ -419,7 +419,7 @@ public interface World extends Extent, Keyed, IChunkCache { } @Override - default String getId() { + default String id() { return getName().replace(" ", "_").toLowerCase(Locale.ROOT); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeTypes.java index 6fe08a295..e8a5e144a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeTypes.java @@ -291,7 +291,7 @@ public final class BiomeTypes { } public static BiomeType register(final BiomeType biome) { - return BiomeType.REGISTRY.register(biome.getId(), biome); + return BiomeType.REGISTRY.register(biome.id(), biome); } public static BiomeType getLegacy(int legacyId) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index 5059c737a..713204843 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -154,7 +154,7 @@ public class BlockState implements BlockStateHolder, Pattern { String input = key.toString(); throw new SuggestInputParseException(Caption.of("fawe.error.invalid-block-type", TextComponent.of(input)), () -> Stream.of( BlockTypesCache.values) - .map(BlockType::getId) + .map(BlockType::id) .filter(id -> StringMan.blockStateMatches(input, id)) .sorted(StringMan.blockStateComparator(input)) .collect(Collectors.toList()) 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 5f6667a13..e40482302 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 @@ -204,14 +204,14 @@ public interface BlockStateHolder> extends TileEnt default String getAsString() { if (getStates().isEmpty()) { - return this.getBlockType().getId(); + return this.getBlockType().id(); } else { String properties = getStates().entrySet().stream() .map(entry -> entry.getKey().getName() + "=" + entry.getValue().toString().toLowerCase(Locale.ROOT)) .collect(Collectors.joining(",")); - return this.getBlockType().getId() + "[" + properties + "]"; + return this.getBlockType().id() + "[" + properties + "]"; } } 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 a2e58a97c..d8b0ae046 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 @@ -124,7 +124,7 @@ public class BlockType implements Keyed, Pattern { * @return The id */ @Override - public String getId() { + public String id() { return this.id; } @@ -135,13 +135,13 @@ public class BlockType implements Keyed, Pattern { //FAWE start public String getNamespace() { - String id = getId(); + String id = id(); int i = id.indexOf(':'); return i == -1 ? "minecraft" : id.substring(0, i); } public String getResource() { - String id = getId(); + String id = id(); return id.substring(id.indexOf(':') + 1); } //FAWE end @@ -156,7 +156,7 @@ public class BlockType implements Keyed, Pattern { public String getName() { String name = this.name.getValue(); if (name == null || name.isEmpty()) { - return getId(); + return id(); } return name; } @@ -180,7 +180,7 @@ public class BlockType implements Keyed, Pattern { LOGGER.error( "Attempted to load blockstate with id {} of type {} outside of state ordinals length. Using default state.", propertyId, - getId() + id() ); return settings.defaultState; } @@ -189,7 +189,7 @@ public class BlockType implements Keyed, Pattern { LOGGER.error( "Attempted to load blockstate with ordinal {} of type {} outside of states length. Using default state. Using default state.", ordinal, - getId() + id() ); return settings.defaultState; } @@ -405,7 +405,7 @@ public class BlockType implements Keyed, Pattern { @Override public String toString() { - return getId(); + return id(); } //FAWE start 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 0206cdf92..2667d44f9 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 @@ -2235,8 +2235,8 @@ public final class BlockTypes { throw new SuggestInputParseException(Caption.of("fawe.error.invalid-block-type", TextComponent.of(input)), () -> Stream.of( BlockTypesCache.values) - .filter(b -> StringMan.blockStateMatches(inputLower, b.getId())) - .map(BlockType::getId) + .filter(b -> StringMan.blockStateMatches(inputLower, b.id())) + .map(BlockType::id) .sorted(StringMan.blockStateComparator(inputLower)) .collect(Collectors.toList()) ); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java index 31bb7606c..a8c2d63c2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java @@ -125,7 +125,7 @@ public class AnvilChunk13 implements Chunk { } catch (IllegalArgumentException e) { throw new InvalidFormatException("Invalid block state for " + blockState .getBlockType() - .getId() + ", " + property.getName() + ": " + value); + .id() + ", " + property.getName() + ": " + value); } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk17.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk17.java index 6d366c295..3789f9a79 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk17.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk17.java @@ -133,7 +133,7 @@ public class AnvilChunk17 implements Chunk { } catch (IllegalArgumentException e) { throw new InvalidFormatException("Invalid block state for " + blockState .getBlockType() - .getId() + ", " + property.getName() + ": " + value); + .id() + ", " + property.getName() + ": " + value); } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java index 4fa50629e..1e36938c4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java @@ -146,7 +146,7 @@ public class AnvilChunk18 implements Chunk { } catch (IllegalArgumentException e) { throw new InvalidFormatException("Invalid block state for " + blockState .getBlockType() - .getId() + ", " + property.getName() + ": " + value); + .id() + ", " + property.getName() + ": " + value); } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategories.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategories.java index 2788fdebe..79569156e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategories.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategories.java @@ -37,7 +37,7 @@ public final class FluidCategories { } public static FluidCategory register(final FluidCategory tag) { - return FluidCategory.REGISTRY.register(tag.getId(), tag); + return FluidCategory.REGISTRY.register(tag.id(), tag); } @Nullable diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidTypes.java index 18c43d8c8..dd5b0270e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidTypes.java @@ -40,7 +40,7 @@ public final class FluidTypes { } public static FluidType register(final FluidType fluid) { - return FluidType.REGISTRY.register(fluid.getId(), fluid); + return FluidType.REGISTRY.register(fluid.id(), fluid); } @Nullable diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameModes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameModes.java index ce87f9ce7..b6d151ba8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameModes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameModes.java @@ -36,7 +36,7 @@ public final class GameModes { } public static GameMode register(final GameMode gameMode) { - return GameMode.REGISTRY.register(gameMode.getId(), gameMode); + return GameMode.REGISTRY.register(gameMode.id(), gameMode); } @Nullable diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java index 5dc7f9277..e7a72b3c9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java @@ -49,7 +49,7 @@ public class ItemType implements RegistryItem, Keyed { .getRegistries().getItemRegistry().getName(this), "" ); - return name.isEmpty() ? getId() : name; + return name.isEmpty() ? id() : name; }); @SuppressWarnings("this-escape") private transient final LazyReference richName = LazyReference.from(() -> @@ -76,7 +76,7 @@ public class ItemType implements RegistryItem, Keyed { } @Override - public String getId() { + public String id() { return this.id; } @@ -153,7 +153,7 @@ public class ItemType implements RegistryItem, Keyed { @Override public String toString() { - return getId(); + return id(); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java index 3f7181397..11663a4f1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java @@ -41,7 +41,7 @@ public class BundledBlockRegistry implements BlockRegistry { @Override public Component getRichName(BlockType blockType) { - BundledBlockData.BlockEntry blockEntry = BundledBlockData.getInstance().findById(blockType.getId()); + BundledBlockData.BlockEntry blockEntry = BundledBlockData.getInstance().findById(blockType.id()); if (blockEntry != null) { // This is more likely to be "right", but not translated // Some vanilla MC blocks have overrides so we need this name here @@ -50,7 +50,7 @@ public class BundledBlockRegistry implements BlockRegistry { return TextComponent.of(blockEntry.localizedName); } return Caption.of( - TranslationManager.makeTranslationKey("block", blockType.getId()) + TranslationManager.makeTranslationKey("block", blockType.id()) ); } @@ -60,14 +60,14 @@ public class BundledBlockRegistry implements BlockRegistry { // dumb_intellij.jpg - Ok?? @SuppressWarnings("deprecation") public String getName(BlockType blockType) { - BundledBlockData.BlockEntry blockEntry = BundledBlockData.getInstance().findById(blockType.getId()); + BundledBlockData.BlockEntry blockEntry = BundledBlockData.getInstance().findById(blockType.id()); return blockEntry != null ? blockEntry.localizedName : null; } @Nullable @Override public BlockMaterial getMaterial(BlockType blockType) { - return new PassthroughBlockMaterial(BundledBlockData.getInstance().getMaterialById(blockType.getId())); + return new PassthroughBlockMaterial(BundledBlockData.getInstance().getMaterialById(blockType.id())); } @Nullable diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemRegistry.java index 2e1d42121..53a707821 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemRegistry.java @@ -34,7 +34,7 @@ import javax.annotation.Nullable; public class BundledItemRegistry implements ItemRegistry { private BundledItemData.ItemEntry getEntryById(ItemType itemType) { - return BundledItemData.getInstance().findById(itemType.getId()); + return BundledItemData.getInstance().findById(itemType.id()); } @Override @@ -48,7 +48,7 @@ public class BundledItemRegistry implements ItemRegistry { return TextComponent.of(itemEntry.localizedName); } return Caption.of( - TranslationManager.makeTranslationKey("item", itemType.getId()) + TranslationManager.makeTranslationKey("item", itemType.id()) ); } @@ -62,7 +62,7 @@ public class BundledItemRegistry implements ItemRegistry { if (itemEntry != null) { String localized = itemEntry.localizedName; if (localized.equals("Air")) { - String id = itemType.getId(); + String id = itemType.id(); int c = id.indexOf(':'); return c < 0 ? id : id.substring(c + 1); } @@ -74,7 +74,7 @@ public class BundledItemRegistry implements ItemRegistry { @Nullable @Override public ItemMaterial getMaterial(ItemType itemType) { - return new PassthroughItemMaterial(BundledItemData.getInstance().getMaterialById(itemType.getId())); + return new PassthroughItemMaterial(BundledItemData.getInstance().getMaterialById(itemType.id())); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java index c52c507b9..dade2d193 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java @@ -38,7 +38,7 @@ public interface CategoryRegistry { Set getCategorisedByName(String category); default Set getAll(final Category category) { - return getCategorisedByName(category.getId()); + return getCategorisedByName(category.id()); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/NullBiomeRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/NullBiomeRegistry.java index 346c94477..19fdd3b88 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/NullBiomeRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/NullBiomeRegistry.java @@ -41,7 +41,7 @@ public class NullBiomeRegistry implements BiomeRegistry { @Override public Component getRichName(BiomeType biomeType) { return Caption.of( - TranslationManager.makeTranslationKey("biome", biomeType.getId()) + TranslationManager.makeTranslationKey("biome", biomeType.id()) ); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherTypes.java index 404e8d6da..458f17f25 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherTypes.java @@ -35,7 +35,7 @@ public final class WeatherTypes { } public static WeatherType register(WeatherType weather) { - return WeatherType.REGISTRY.register(weather.getId(), weather); + return WeatherType.REGISTRY.register(weather.id(), weather); } @Nullable From 865cc55a0e08ac73e255a1afafb69c7a42081221 Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 13 Jun 2024 20:31:34 +0200 Subject: [PATCH 276/466] feat: add #hotbar mask and pattern (#2769) - closes #2765 --- .../bukkit/BukkitPlayerBlockBag.java | 3 + .../factory/parser/common/HotbarParser.java | 72 +++++++++++++++++++ .../factory/parser/mask/HotbarMaskParser.java | 20 ++++++ .../parser/pattern/HotbarPatternParser.java | 26 +++++++ .../extension/factory/MaskFactory.java | 2 + .../extension/factory/PatternFactory.java | 3 + .../extension/input/ParserContext.java | 15 ++++ .../src/main/resources/lang/strings.json | 2 + 8 files changed, 143 insertions(+) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/common/HotbarParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/HotbarMaskParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/HotbarPatternParser.java diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayerBlockBag.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayerBlockBag.java index b060d78f8..2ad20fb6f 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayerBlockBag.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayerBlockBag.java @@ -192,6 +192,9 @@ public class BukkitPlayerBlockBag extends BlockBag implements SlottableBlockBag @Override public BaseItem getItem(int slot) { loadInventory(); + if (items[slot] == null) { + return null; + } return BukkitAdapter.adapt(items[slot]); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/common/HotbarParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/common/HotbarParser.java new file mode 100644 index 000000000..0fe104990 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/common/HotbarParser.java @@ -0,0 +1,72 @@ +package com.fastasyncworldedit.core.extension.factory.parser.common; + +import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.extent.inventory.SlottableBlockBag; +import com.fastasyncworldedit.core.limit.FaweLimit; +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.entity.Player; +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.extent.inventory.BlockBag; +import com.sk89q.worldedit.internal.registry.SimpleInputParser; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.world.block.BlockType; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +public abstract class HotbarParser extends SimpleInputParser { + + private final List aliases = ImmutableList.of("#hotbar"); + + protected HotbarParser(final WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public List getMatchedAliases() { + return aliases; + } + + protected List getBlockTypes(ParserContext context) { + Player player = context.requirePlayer(); + BlockBag bag = player.getInventoryBlockBag(); + if (!(bag instanceof final SlottableBlockBag slottable)) { + // Matches DefaultBlockParser + throw new InputParseException(Caption.of("fawe.error.unsupported")); + } + List types = new ArrayList<>(); + FaweLimit limit = player.getLimit(); + boolean anyBlock = player.hasPermission("worldedit.anyblock"); + for (int slot = 0; slot < 9; slot++) { + BaseItem item = slottable.getItem(slot); + if (item != null && item.getType().hasBlockType()) { + BlockType type = item.getType().getBlockType(); + if (!anyBlock && worldEdit.getConfiguration().disallowedBlocks.contains(type.id().toLowerCase(Locale.ROOT))) { + throw new DisallowedUsageException(Caption.of( + "worldedit.error.disallowed-block", + TextComponent.of(type.getId()) + )); + } + if (!limit.isUnlimited()) { + if (limit.DISALLOWED_BLOCKS.contains(type.id().toLowerCase(Locale.ROOT))) { + throw new DisallowedUsageException(Caption.of( + "fawe.error.limit.disallowed-block", + TextComponent.of(type.getId()) + )); + } + } + types.add(type); + } + } + if (types.isEmpty()) { + throw new InputParseException(Caption.of("fawe.error.no-valid-on-hotbar")); + } + return types; + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/HotbarMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/HotbarMaskParser.java new file mode 100644 index 000000000..4f56ae109 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/HotbarMaskParser.java @@ -0,0 +1,20 @@ +package com.fastasyncworldedit.core.extension.factory.parser.mask; + +import com.fastasyncworldedit.core.extension.factory.parser.common.HotbarParser; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.BlockTypeMask; +import com.sk89q.worldedit.function.mask.Mask; + +public class HotbarMaskParser extends HotbarParser { + + public HotbarMaskParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Mask parseFromSimpleInput(String input, ParserContext context) { + return new BlockTypeMask(context.getExtent(), getBlockTypes(context)); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/HotbarPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/HotbarPatternParser.java new file mode 100644 index 000000000..2f1db622e --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/HotbarPatternParser.java @@ -0,0 +1,26 @@ +package com.fastasyncworldedit.core.extension.factory.parser.pattern; + +import com.fastasyncworldedit.core.extension.factory.parser.common.HotbarParser; +import com.fastasyncworldedit.core.math.random.TrueRandom; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.pattern.RandomPattern; +import com.sk89q.worldedit.world.block.BlockType; + +public class HotbarPatternParser extends HotbarParser { + + public HotbarPatternParser(WorldEdit worldEdit) { + super(worldEdit); + } + + @Override + public Pattern parseFromSimpleInput(String input, ParserContext context) { + RandomPattern random = new RandomPattern(new TrueRandom()); + for (BlockType type : getBlockTypes(context)) { + random.add(type, 1); + } + return random; + } + +} 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 5c8ff7d6f..cf126560e 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 @@ -25,6 +25,7 @@ import com.fastasyncworldedit.core.extension.factory.parser.mask.AngleMaskParser import com.fastasyncworldedit.core.extension.factory.parser.mask.BesideMaskParser; import com.fastasyncworldedit.core.extension.factory.parser.mask.ExtremaMaskParser; import com.fastasyncworldedit.core.extension.factory.parser.mask.FalseMaskParser; +import com.fastasyncworldedit.core.extension.factory.parser.mask.HotbarMaskParser; import com.fastasyncworldedit.core.extension.factory.parser.mask.LiquidMaskParser; import com.fastasyncworldedit.core.extension.factory.parser.mask.ROCAngleMaskParser; import com.fastasyncworldedit.core.extension.factory.parser.mask.RadiusMaskParser; @@ -110,6 +111,7 @@ public final class MaskFactory extends AbstractFactory { register(new BesideMaskParser(worldEdit)); register(new ExtremaMaskParser(worldEdit)); register(new FalseMaskParser(worldEdit)); + register(new HotbarMaskParser(worldEdit)); register(new LiquidMaskParser(worldEdit)); register(new RadiusMaskParser(worldEdit)); register(new RichOffsetMaskParser(worldEdit)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java index a76759833..b31d801b3 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 @@ -20,6 +20,7 @@ package com.sk89q.worldedit.extension.factory; import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.extension.factory.parser.mask.HotbarMaskParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.AngleColorPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.AverageColorPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.BiomePatternParser; @@ -30,6 +31,7 @@ import com.fastasyncworldedit.core.extension.factory.parser.pattern.DarkenPatter import com.fastasyncworldedit.core.extension.factory.parser.pattern.DesaturatePatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.ExistingPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.ExpressionPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.HotbarPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.LightenPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.Linear2DPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.Linear3DPatternParser; @@ -116,6 +118,7 @@ public final class PatternFactory extends AbstractFactory { register(new DesaturatePatternParser(worldEdit)); register(new ExistingPatternParser(worldEdit)); register(new ExpressionPatternParser(worldEdit)); + register(new HotbarPatternParser(worldEdit)); register(new LightenPatternParser(worldEdit)); register(new Linear2DPatternParser(worldEdit)); register(new Linear3DPatternParser(worldEdit)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java index 430280814..989931b0b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java @@ -23,6 +23,7 @@ import com.fastasyncworldedit.core.configuration.Caption; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.factory.MaskFactory; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; @@ -217,6 +218,20 @@ public class ParserContext { return actor; } + /** + * Get the {@link Player} set on this context. + * + * @return a player + * @throws InputParseException thrown if no {@link Actor} is set + */ + public Player requirePlayer() throws InputParseException { + Actor actor = getActor(); + if (!(actor instanceof Player player)) { + throw new InputParseException(Caption.of("worldedit.error.missing-player")); + } + return player; + } + /** * Returns whether there should be restrictions (as a result of * limits or permissions) considered when parsing the input. diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index c67da38d7..a8dddbdcf 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -139,6 +139,7 @@ "fawe.error.occurred-continuing": "Ignorable error occurred during edit: {0}", "fawe.error.limit.max-brush-radius": "Maximum brush radius in limit: {0}", "fawe.error.limit.max-radius": "Maximum radius in limit: {0}", + "fawe.error.no-valid-on-hotbar": "No valid block types on hotbar", "fawe.cancel.count": "Cancelled {0} edits.", "fawe.cancel.reason.confirm": "Use //confirm to execute {0}", "fawe.cancel.reason.confirm.region": "Your selection is large ({0} -> {1}, containing {3} blocks). Use //confirm to execute {2}", @@ -240,6 +241,7 @@ "worldedit.error.missing-session": "No LocalSession is known", "worldedit.error.missing-world": "You need to provide a world (Try //world)", "worldedit.error.missing-actor": "No actor is known", + "worldedit.error.missing-player": "No player is known", "worldedit.error.no-file-selected": "No file selected.", "worldedit.error.file-resolution.outside-root": "Path is outside allowable root", "worldedit.error.file-resolution.resolve-failed": "Failed to resolve path", From 031fdf2efd6c477d4d1b5bdb80db44989d9e99cd Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 13 Jun 2024 20:31:45 +0200 Subject: [PATCH 277/466] fix: ensure config-legacy.yml is created before accessed (#2752) * fix: ensure config-legacy.yml is created before accessed * Stop error attempting to load FAWE config if it doesn't exist --- .../java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java | 8 ++++---- .../com/fastasyncworldedit/core/configuration/Config.java | 3 +++ .../core/configuration/file/YamlConfiguration.java | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java index b4556409c..faac1c955 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 @@ -137,6 +137,10 @@ public class WorldEditPlugin extends JavaPlugin { //noinspection ResultOfMethodCallIgnored getDataFolder().mkdirs(); + //FAWE start - Migrate from config-legacy to worldedit-config + migrateLegacyConfig(); + //FAWE end + //FAWE start - Modify WorldEdit config name config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "worldedit-config.yml"), true), this); // Load config before we say we've loaded platforms as it is used in listeners of the event @@ -151,10 +155,6 @@ public class WorldEditPlugin extends JavaPlugin { platform = new BukkitServerInterface(this, getServer()); worldEdit.getPlatformManager().register(platform); - //FAWE start - Migrate from config-legacy to worldedit-config - migrateLegacyConfig(); - //FAWE end - //FAWE start - Setup permission attachments permissionAttachmentManager = new BukkitPermissionAttachmentManager(this); //FAWE end diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java index e5185e6d8..d230ab05b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java @@ -100,6 +100,9 @@ public class Config { } public boolean load(File file) { + if (!file.exists()) { + return false; + } existingMigrateNodes = new ArrayList<>(); YamlConfiguration yml = YamlConfiguration.loadConfiguration(file); for (String key : yml.getKeys(true)) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/file/YamlConfiguration.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/file/YamlConfiguration.java index 1e2d5b0c4..f900451b5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/file/YamlConfiguration.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/file/YamlConfiguration.java @@ -68,6 +68,7 @@ public class YamlConfiguration extends FileConfiguration { LOGGER.error("Could not read {}\n" + "Renamed to {}", file, dest.getAbsolutePath(), ex); } catch (final IOException e) { e.printStackTrace(); + ex.printStackTrace(); } } From 4a5ff8e306151f553764848744cd3a8bcc5e16e3 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Fri, 14 Jun 2024 19:18:35 +0100 Subject: [PATCH 278/466] fix: wrap immutable map in MinecraftStructure writer - fixes #2781 --- .../extent/clipboard/io/schematic/MinecraftStructure.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java index 0779418df..c1f129112 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java @@ -236,11 +236,11 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { BaseEntity state = entity.getState(); if (state != null) { CompoundTag nbt = state.getNbtData(); - Map nbtMap = nbt.getValue(); + Map nbtMap = new HashMap<>(nbt.getValue()); // Replace rotation data nbtMap.put("Rotation", writeRotation(entity.getLocation())); nbtMap.put("id", new StringTag(state.getType().id())); - Map entityMap = FaweCache.INSTANCE.asMap("pos", pos, "blockPos", blockPos, "nbt", nbt); + Map entityMap = FaweCache.INSTANCE.asMap("pos", pos, "blockPos", blockPos, "nbt", new CompoundTag(nbtMap)); entities.add(entityMap); } } From 8aba1e6c06e3bf0e3065891e5c2ce0c5e8087e27 Mon Sep 17 00:00:00 2001 From: Jordan Date: Sat, 15 Jun 2024 13:07:29 +0200 Subject: [PATCH 279/466] fix: allow use of quotes to allow spaces to be used as "and" (#2786) * fix: allow use of quotes to allow spaces to be sued as "and" - e.g. `//set "#mask[grass_block& { - private final RichTransformParser richTransformParser; - /** * Create a new factory. * * @param worldEdit the WorldEdit instance */ public TransformFactory(WorldEdit worldEdit) { - super(worldEdit, new NullTransformParser(worldEdit)); - - richTransformParser = new RichTransformParser(worldEdit); + super(worldEdit, new NullTransformParser(worldEdit), new RichTransformParser(worldEdit)); // split and parse each sub-transform register(new RandomTransformParser(worldEdit)); @@ -51,68 +46,7 @@ public class TransformFactory extends AbstractFactory { } @Override - public ResettableExtent parseFromInput(String input, ParserContext context) throws InputParseException { - List transforms = new ArrayList<>(); - - for (String component : input.split(" ")) { - if (component.isEmpty()) { - continue; - } - - ResettableExtent match = richTransformParser.parseFromInput(component, context); - if (match != null) { - transforms.add(match); - continue; - } - parseFromParsers(context, transforms, component); - } - - return getResettableExtent(input, transforms); - } - - private void parseFromParsers( - final ParserContext context, - final List transforms, - final String component - ) { - ResettableExtent match = null; - for (InputParser parser : getParsers()) { - match = parser.parseFromInput(component, context); - - if (match != null) { - break; - } - } - if (match == null) { - throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(component))); - } - transforms.add(match); - } - - /** - * Parses a transform without considering parsing through the {@link RichTransformParser}, therefore not accepting - * "richer" parsing where & and , are used. Exists to prevent stack overflows. - * - * @param input input string - * @param context input context - * @return parsed result - * @throws InputParseException if no result found - */ - public ResettableExtent parseWithoutRich(String input, ParserContext context) throws InputParseException { - List transforms = new ArrayList<>(); - - for (String component : input.split(" ")) { - if (component.isEmpty()) { - continue; - } - - parseFromParsers(context, transforms, component); - } - - return getResettableExtent(input, transforms); - } - - private ResettableExtent getResettableExtent(final String input, final List transforms) { + protected ResettableExtent getParsed(final String input, final List transforms) { switch (transforms.size()) { case 0: throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input))); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/FaweParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/FaweParser.java index 11d33ef67..08dd05ad1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/FaweParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/FaweParser.java @@ -37,14 +37,14 @@ public abstract class FaweParser extends InputParser implements AliasedPar for (int i = 0; i < toParse.length(); i++) { char c = toParse.charAt(i); switch (c) { - case ',', '&' -> { + case ',', '&', ' ' -> { if (expression) { continue; } String result = toParse.substring(last, i); if (!result.isEmpty()) { inputs.add(result); - and.add(c == '&'); + and.add(c == '&' || c == ' '); } else { throw new InputParseException(Caption.of("fawe.error.parse.invalid-dangling-character", c)); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java index 14ecb48f1..f436ce576 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java @@ -23,11 +23,16 @@ import com.sk89q.util.StringUtil; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.factory.parser.DefaultBlockParser; import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.internal.registry.AbstractFactory; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.world.block.BaseBlock; import java.util.HashSet; +import java.util.List; import java.util.Set; /** @@ -67,4 +72,21 @@ public class BlockFactory extends AbstractFactory { return blocks; } + //FAWE start + @Override + public BaseBlock parseFromInput(String input, ParserContext context) throws InputParseException { + BaseBlock match; + + for (InputParser parser : parsers) { + match = parser.parseFromInput(input, context); + + if (match != null) { + return match; + } + } + + throw new NoMatchException(TranslatableComponent.of("worldedit.error.no-match", TextComponent.of(input))); + } + //FAWE end + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/ItemFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/ItemFactory.java index b1858a12d..8c907f42a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/ItemFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/ItemFactory.java @@ -22,7 +22,13 @@ package com.sk89q.worldedit.extension.factory; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.extension.factory.parser.DefaultItemParser; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.internal.registry.AbstractFactory; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; public class ItemFactory extends AbstractFactory { @@ -35,4 +41,21 @@ public class ItemFactory extends AbstractFactory { super(worldEdit, new DefaultItemParser(worldEdit)); } + //FAWE start + @Override + public BaseItem parseFromInput(String input, ParserContext context) throws InputParseException { + BaseItem match; + + for (InputParser parser : parsers) { + match = parser.parseFromInput(input, context); + + if (match != null) { + return match; + } + } + + throw new NoMatchException(TranslatableComponent.of("worldedit.error.no-match", TextComponent.of(input))); + } + //FAWE end + } 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 cf126560e..3440b009c 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 @@ -53,16 +53,13 @@ import com.sk89q.worldedit.extension.factory.parser.mask.NoiseMaskParser; import com.sk89q.worldedit.extension.factory.parser.mask.OffsetMaskParser; import com.sk89q.worldedit.extension.factory.parser.mask.RegionMaskParser; import com.sk89q.worldedit.extension.factory.parser.mask.SolidMaskParser; -import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.NoMatchException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.MaskIntersection; import com.sk89q.worldedit.internal.registry.AbstractFactory; -import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.util.formatting.text.TextComponent; -import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -75,21 +72,13 @@ import java.util.stream.Collectors; */ public final class MaskFactory extends AbstractFactory { - //FAWE start - rich mask parsing - private final RichMaskParser richMaskParser; - //FAWE end - /** * Create a new mask registry. * * @param worldEdit the WorldEdit instance */ public MaskFactory(WorldEdit worldEdit) { - super(worldEdit, new BlocksMaskParser(worldEdit)); - - //FAWE start - rich mask parsing - richMaskParser = new RichMaskParser(worldEdit); - //FAWE end + super(worldEdit, new BlocksMaskParser(worldEdit), new RichMaskParser(worldEdit)); register(new ExistingMaskParser(worldEdit)); register(new AirMaskParser(worldEdit)); @@ -125,7 +114,6 @@ public final class MaskFactory extends AbstractFactory { register(new ZAxisMaskParser(worldEdit)); register(new SurfaceAngleMaskParser(worldEdit)); //FAWE end - } @Override @@ -133,85 +121,24 @@ public final class MaskFactory extends AbstractFactory { final String[] split = input.split(" "); if (split.length > 1) { String prev = input.substring(0, input.lastIndexOf(" ")) + " "; - return super.getSuggestions(split[split.length - 1], parserContext).stream().map(s -> prev + s).collect(Collectors.toList()); + return super + .getSuggestions(split[split.length - 1], parserContext) + .stream() + .map(s -> prev + s) + .collect(Collectors.toList()); } return super.getSuggestions(input, parserContext); } - @Override - public Mask parseFromInput(String input, ParserContext context) throws InputParseException { - List masks = new ArrayList<>(); - - for (String component : input.split(" ")) { - if (component.isEmpty()) { - continue; - } - - //FAWE start - rich mask parsing - Mask match = richMaskParser.parseFromInput(component, context); - if (match != null) { - masks.add(match); - continue; - } - parseFromParsers(context, masks, component); - //FAWE end - } - - return getMask(input, masks); - } - //FAWE start - rich mask parsing - private void parseFromParsers( - final ParserContext context, - final List masks, - final String component - ) { - Mask match = null; - for (InputParser parser : getParsers()) { - match = parser.parseFromInput(component, context); - if (match != null) { - break; - } - } - if (match == null) { - throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(component))); - } - masks.add(match); - } - - /** - * Parses a mask without considering parsing through the {@link RichMaskParser}, therefore not accepting - * "richer" parsing where & and , are used. Exists to prevent stack overflows. - * - * @param input input string - * @param context input context - * @return parsed result - * @throws InputParseException if no result found - */ - public Mask parseWithoutRich(String input, ParserContext context) throws InputParseException { - List masks = new ArrayList<>(); - - for (String component : input.split(" ")) { - if (component.isEmpty()) { - continue; - } - - parseFromParsers(context, masks, component); - } - - return getMask(input, masks); - } - - private Mask getMask(final String input, final List masks) { - switch (masks.size()) { - case 0: - throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input))); - case 1: - return masks.get(0).optimize(); - default: - return new MaskIntersection(masks).optimize(); - } + @Override + protected Mask getParsed(final String input, final List masks) { + return switch (masks.size()) { + case 0 -> throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input))); + case 1 -> masks.get(0).optimize(); + default -> new MaskIntersection(masks).optimize(); + }; } //FAWE end 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 b31d801b3..25955adee 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 @@ -20,7 +20,6 @@ package com.sk89q.worldedit.extension.factory; import com.fastasyncworldedit.core.configuration.Caption; -import com.fastasyncworldedit.core.extension.factory.parser.mask.HotbarMaskParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.AngleColorPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.AverageColorPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.BiomePatternParser; @@ -44,8 +43,6 @@ import com.fastasyncworldedit.core.extension.factory.parser.pattern.OffsetPatter import com.fastasyncworldedit.core.extension.factory.parser.pattern.PerlinPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.RandomFullClipboardPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.RandomOffsetPatternParser; -import com.fastasyncworldedit.core.extension.factory.parser.pattern.TypeSwapPatternParser; -import com.sk89q.worldedit.extension.factory.parser.pattern.RandomPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.RelativePatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.RichPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.RidgedMultiFractalPatternParser; @@ -53,24 +50,22 @@ import com.fastasyncworldedit.core.extension.factory.parser.pattern.SaturatePatt import com.fastasyncworldedit.core.extension.factory.parser.pattern.SimplexPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.SolidRandomOffsetPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.SurfaceRandomOffsetPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.TypeSwapPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.VoronoiPatternParser; import com.fastasyncworldedit.core.math.random.TrueRandom; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.factory.parser.pattern.BlockCategoryPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.ClipboardPatternParser; +import com.sk89q.worldedit.extension.factory.parser.pattern.RandomPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.RandomStatePatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.SingleBlockPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.TypeOrStateApplyingPatternParser; -import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.NoMatchException; -import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.RandomPattern; import com.sk89q.worldedit.internal.registry.AbstractFactory; -import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.util.formatting.text.TextComponent; -import java.util.ArrayList; import java.util.List; /** @@ -82,20 +77,14 @@ import java.util.List; */ public final class PatternFactory extends AbstractFactory { - //FAWE start - rich pattern parsing - private final RichPatternParser richPatternParser; - //FAWE end - /** * Create a new instance. * * @param worldEdit the WorldEdit instance */ public PatternFactory(WorldEdit worldEdit) { - super(worldEdit, new SingleBlockPatternParser(worldEdit)); - //FAWE start - rich pattern parsing - richPatternParser = new RichPatternParser(worldEdit); + super(worldEdit, new SingleBlockPatternParser(worldEdit), new RichPatternParser(worldEdit)); //FAWE end // split and parse each sub-pattern @@ -139,75 +128,10 @@ public final class PatternFactory extends AbstractFactory { register(new SurfaceRandomOffsetPatternParser(worldEdit)); register(new TypeSwapPatternParser(worldEdit)); register(new VoronoiPatternParser(worldEdit)); - //FAWE end } @Override - public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { - List patterns = new ArrayList<>(); - - for (String component : input.split(" ")) { - if (component.isEmpty()) { - continue; - } - - //FAWE start - rich pattern parsing - Pattern match = richPatternParser.parseFromInput(component, context); - if (match != null) { - patterns.add(match); - continue; - } - parseFromParsers(context, patterns, component); - //FAWE end - } - - return getPattern(input, patterns); - } - - //FAWE start - rich pattern parsing - private void parseFromParsers( - final ParserContext context, - final List patterns, - final String component - ) { - Pattern match = null; - for (InputParser parser : getParsers()) { - match = parser.parseFromInput(component, context); - - if (match != null) { - break; - } - } - if (match == null) { - throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(component))); - } - patterns.add(match); - } - - /** - * Parses a pattern without considering parsing through the {@link RichPatternParser}, therefore not accepting - * "richer" parsing where & and , are used. Exists to prevent stack overflows. - * - * @param input input string - * @param context input context - * @return parsed result - * @throws InputParseException if no result found - */ - public Pattern parseWithoutRich(String input, ParserContext context) throws InputParseException { - List patterns = new ArrayList<>(); - - for (String component : input.split(" ")) { - if (component.isEmpty()) { - continue; - } - - parseFromParsers(context, patterns, component); - } - - return getPattern(input, patterns); - } - - private Pattern getPattern(final String input, final List patterns) { + protected Pattern getParsed(final String input, final List patterns) { switch (patterns.size()) { case 0: throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input))); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java index 237dd1c4c..0934627b9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java @@ -21,6 +21,9 @@ package com.sk89q.worldedit.internal.registry; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.extension.factory.parser.AliasedParser; +import com.fastasyncworldedit.core.extension.factory.parser.FaweParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.RichPatternParser; +import com.sk89q.util.StringUtil; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.NoMatchException; @@ -43,7 +46,10 @@ import static com.google.common.base.Preconditions.checkNotNull; public abstract class AbstractFactory { protected final WorldEdit worldEdit; - private final List> parsers = new ArrayList<>(); + //FAWE start + protected final List> parsers = new ArrayList<>(); + private final FaweParser richParser; + //FWAE end /** * Create a new factory. @@ -52,11 +58,26 @@ public abstract class AbstractFactory { * @param defaultParser the parser to fall back to */ protected AbstractFactory(WorldEdit worldEdit, InputParser defaultParser) { + //FAWE start + this(worldEdit, defaultParser, null); + } + + /** + * Create a new factory with a given rich parser for FAWE rich parsing + * + * @param worldEdit the WorldEdit instance + * @param defaultParser the parser to fall back to + * @param richParser the rich parser + * @since TODO + */ + protected AbstractFactory(WorldEdit worldEdit, InputParser defaultParser, FaweParser richParser) { checkNotNull(worldEdit); checkNotNull(defaultParser); this.worldEdit = worldEdit; this.parsers.add(defaultParser); + this.richParser = richParser; } + //FAWE end /** * Gets an immutable list of parsers. @@ -71,7 +92,7 @@ public abstract class AbstractFactory { return Collections.unmodifiableList(parsers); } - //FAWE start - javadoc + //FAWE start /** * Parse a string and context to each {@link InputParser} added to this factory. If no result found, throws {@link InputParseException} @@ -81,20 +102,26 @@ public abstract class AbstractFactory { * @return parsed result * @throws InputParseException if no result found */ - //FAWE end public E parseFromInput(String input, ParserContext context) throws InputParseException { - E match; - - for (InputParser parser : parsers) { - match = parser.parseFromInput(input, context); - - if (match != null) { - return match; + List parsed = new ArrayList<>(); + for (String component : StringUtil.split(input,' ', '[', ']')) { + if (component.isEmpty()) { + continue; } + + if (richParser != null) { + E match = richParser.parseFromInput(component, context); + if (match != null) { + parsed.add(match); + continue; + } + } + parseFromParsers(context, parsed, component); } - throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input))); + return getParsed(input, parsed); } + //FAWE end @Deprecated public List getSuggestions(String input) { @@ -133,4 +160,48 @@ public abstract class AbstractFactory { }); } + //FAWE start + protected void parseFromParsers(final ParserContext context, final List parsed, final String component) { + E match = null; + for (InputParser parser : getParsers()) { + match = parser.parseFromInput(component, context); + + if (match != null) { + break; + } + } + if (match == null) { + throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(component))); + } + parsed.add(match); + } + + /** + * Parses a pattern without considering parsing through the {@link RichPatternParser}, therefore not accepting + * "richer" parsing where & and , are used. Exists to prevent stack overflows. + * + * @param input input string + * @param context input context + * @return parsed result + * @throws InputParseException if no result found + */ + public E parseWithoutRich(String input, ParserContext context) throws InputParseException { + List parsed = new ArrayList<>(); + + for (String component : StringUtil.split(input, ' ', '[', ']')) { + if (component.isEmpty()) { + continue; + } + + parseFromParsers(context, parsed, component); + } + + return getParsed(input, parsed); + } + + protected E getParsed(final String input, final List parsed) { + return parsed.isEmpty() ? null : parsed.get(0); + } + //FAWE end + } From af83b2f9c9a1a2fca87715b10d34367b8377cb45 Mon Sep 17 00:00:00 2001 From: Jordan Date: Sat, 15 Jun 2024 13:08:42 +0200 Subject: [PATCH 280/466] fix: improve biome setting to avoid writing directly to chunk (#2757) * fix: improve biome setting to avoid writing directly to chunk - Removes possibility of writing to the LevelChunkSection biomes PalettedContainer whilst it is being read for sending packets - I believe this occured mostly on clipboard operations where blocks are written before biomes, so chunks are being sent whilst writing biomes - This would explain why the error reported in the below issue (and others) is/was so rare - Of course I could be completely wrong about all of this, but given the line in LevelChunkSection#write that the error seems to consistently occur on is when writing biomes to the packet, and that the only place I can find in FAWE where we write to a "live" PalettedContainer is for biomes, I am reasonably confident that this is the cause - Should address #2729 * Remove self-refraction-check --- .../fawe/v1_19_R3/PaperweightGetBlocks.java | 49 ++++++------ .../v1_19_R3/PaperweightPlatformAdapter.java | 14 +++- .../fawe/v1_20_R1/PaperweightGetBlocks.java | 49 ++++++------ .../v1_20_R1/PaperweightPlatformAdapter.java | 18 +++-- .../fawe/v1_20_R2/PaperweightGetBlocks.java | 76 +++++++++++------- .../v1_20_R2/PaperweightPlatformAdapter.java | 18 +++-- .../fawe/v1_20_R3/PaperweightGetBlocks.java | 76 +++++++++++------- .../v1_20_R3/PaperweightPlatformAdapter.java | 17 ++-- .../fawe/v1_20_R4/PaperweightGetBlocks.java | 80 ++++++++++++------- .../v1_20_R4/PaperweightPlatformAdapter.java | 19 +++-- 10 files changed, 252 insertions(+), 164 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java index abf0aa9f0..4d979fd0e 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java @@ -511,7 +511,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } } } else { - setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); + PalettedContainer> paletteBiomes = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); + if (paletteBiomes != null) { + PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes); + } } } } @@ -553,11 +560,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (existingSection == null) { PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId( - BiomeTypes.PLAINS)), + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), PalettedContainer.Strategy.SECTION_BIOMES, null ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); @@ -625,15 +628,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc existingSection.getBiomes() ); - newSection = - PaperweightPlatformAdapter.newChunkSection( - layerNo, - this::loadPrivately, - setArr, - adapter, - biomeRegistry, - biomeData - ); + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + this::loadPrivately, + setArr, + adapter, + biomeRegistry, + biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() + ); if (!PaperweightPlatformAdapter.setSectionAtomic( levelChunkSections, existingSection, @@ -845,7 +847,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (callback == null) { if (finalizer != null) { - finalizer.run(); + queueHandler.async(finalizer, null); } return null; } else { @@ -1103,9 +1105,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc final int sectionIndex, final PalettedContainerRO> data ) { + BiomeType[] sectionBiomes; + if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { + return null; + } PalettedContainer> biomeData; if (data instanceof PalettedContainer> palettedContainer) { - biomeData = palettedContainer; + biomeData = palettedContainer.copy(); } else { LOGGER.warn( "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + @@ -1115,10 +1121,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc ); biomeData = data.recreate(); } - BiomeType[] sectionBiomes; - if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { - return biomeData; - } for (int y = 0, index = 0; y < 4; y++) { for (int z = 0; z < 4; z++) { for (int x = 0; x < 4; x++, index++) { @@ -1130,10 +1132,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc x, y, z, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId(biomeType)) + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) ); } } diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java index 0a7453578..ccd6ed982 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java @@ -98,7 +98,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingFluidCount; private static final Field fieldTickingBlockCount; - private static final Field fieldNonEmptyBlockCount; + private static final Field fieldBiomes; private static final MethodHandle methodGetVisibleChunk; @@ -139,8 +139,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g")); fieldTickingBlockCount.setAccessible(true); - fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f")); - fieldNonEmptyBlockCount.setAccessible(true); + fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "j")); + fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", @@ -502,6 +502,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return new LevelChunkSection(layer, dataPaletteBlocks, biomes); } + public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer> biomes) { + try { + fieldBiomes.set(section, biomes); + } catch (IllegalAccessException e) { + LOGGER.error("Could not set biomes to chunk section", e); + } + } + /** * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. */ diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java index e0232f996..cc329c16a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java @@ -510,7 +510,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } } } else { - setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); + PalettedContainer> paletteBiomes = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); + if (paletteBiomes != null) { + PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes); + } } } } @@ -552,11 +559,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (existingSection == null) { PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId( - BiomeTypes.PLAINS)), + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), PalettedContainer.Strategy.SECTION_BIOMES ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); newSection = PaperweightPlatformAdapter.newChunkSection( @@ -623,15 +626,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc existingSection.getBiomes() ); - newSection = - PaperweightPlatformAdapter.newChunkSection( - layerNo, - this::loadPrivately, - setArr, - adapter, - biomeRegistry, - biomeData - ); + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + this::loadPrivately, + setArr, + adapter, + biomeRegistry, + biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() + ); if (!PaperweightPlatformAdapter.setSectionAtomic( levelChunkSections, existingSection, @@ -843,7 +845,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (callback == null) { if (finalizer != null) { - finalizer.run(); + queueHandler.async(finalizer, null); } return null; } else { @@ -1100,9 +1102,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc final int sectionIndex, final PalettedContainerRO> data ) { + BiomeType[] sectionBiomes; + if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { + return null; + } PalettedContainer> biomeData; if (data instanceof PalettedContainer> palettedContainer) { - biomeData = palettedContainer; + biomeData = palettedContainer.copy(); } else { LOGGER.warn( "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + @@ -1112,10 +1118,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc ); biomeData = data.recreate(); } - BiomeType[] sectionBiomes; - if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { - return biomeData; - } for (int y = 0, index = 0; y < 4; y++) { for (int z = 0; z < 4; z++) { for (int x = 0; x < 4; x++, index++) { @@ -1127,10 +1129,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc x, y, z, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId(biomeType)) + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) ); } } diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java index 74eec9195..999dd3646 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java @@ -62,7 +62,6 @@ import net.minecraft.world.level.entity.PersistentEntitySectionManager; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_20_R1.CraftChunk; -import sun.misc.Unsafe; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -102,7 +101,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingFluidCount; private static final Field fieldTickingBlockCount; - private static final Field fieldNonEmptyBlockCount; private static final MethodHandle methodGetVisibleChunk; @@ -111,6 +109,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodremoveTickingBlockEntity; + private static final Field fieldBiomes; private static final Field fieldOffers; private static final MerchantOffers OFFERS = new MerchantOffers(); @@ -149,8 +148,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount.setAccessible(true); - fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e")); - fieldNonEmptyBlockCount.setAccessible(true); + fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i")); + fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", @@ -417,7 +416,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @Nullable PalettedContainer> biomes ) { if (set == null) { - return newChunkSection(layer, biomeRegistry, biomes); + return newChunkSection(biomeRegistry, biomes); } final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); @@ -507,7 +506,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @SuppressWarnings("deprecation") // Only deprecated in paper private static LevelChunkSection newChunkSection( - int layer, Registry biomeRegistry, @Nullable PalettedContainer> biomes ) { @@ -522,6 +520,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return new LevelChunkSection(dataPaletteBlocks, biomes); } + public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer> biomes) { + try { + fieldBiomes.set(section, biomes); + } catch (IllegalAccessException e) { + LOGGER.error("Could not set biomes to chunk section", e); + } + } + /** * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. */ diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java index 08ba39b10..f5492fccb 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java @@ -29,7 +29,11 @@ import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BlockTypesCache; import io.papermc.lib.PaperLib; import io.papermc.paper.event.block.BeaconDeactivatedEvent; -import net.minecraft.core.*; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.IdMap; +import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.nbt.IntTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; @@ -42,7 +46,14 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.entity.BeaconBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.*; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.HashMapPalette; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.LinearPalette; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.lighting.LevelLightEngine; import org.apache.logging.log4j.Logger; @@ -52,7 +63,17 @@ import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; import javax.annotation.Nonnull; -import java.util.*; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; @@ -497,7 +518,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } } } else { - setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); + PalettedContainer> paletteBiomes = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); + if (paletteBiomes != null) { + PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes); + } } } } @@ -539,11 +567,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (existingSection == null) { PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId( - BiomeTypes.PLAINS)), + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), PalettedContainer.Strategy.SECTION_BIOMES ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); newSection = PaperweightPlatformAdapter.newChunkSection( @@ -610,15 +634,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc existingSection.getBiomes() ); - newSection = - PaperweightPlatformAdapter.newChunkSection( - layerNo, - this::loadPrivately, - setArr, - adapter, - biomeRegistry, - biomeData - ); + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + this::loadPrivately, + setArr, + adapter, + biomeRegistry, + biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() + ); if (!PaperweightPlatformAdapter.setSectionAtomic( levelChunkSections, existingSection, @@ -830,7 +853,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (callback == null) { if (finalizer != null) { - finalizer.run(); + queueHandler.async(finalizer, null); } return null; } else { @@ -1087,9 +1110,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc final int sectionIndex, final PalettedContainerRO> data ) { + BiomeType[] sectionBiomes; + if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { + return null; + } PalettedContainer> biomeData; if (data instanceof PalettedContainer> palettedContainer) { - biomeData = palettedContainer; + biomeData = palettedContainer.copy(); } else { LOGGER.warn( "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + @@ -1099,10 +1126,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc ); biomeData = data.recreate(); } - BiomeType[] sectionBiomes; - if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { - return biomeData; - } for (int y = 0, index = 0; y < 4; y++) { for (int z = 0; z < 4; z++) { for (int x = 0; x < 4; x++, index++) { @@ -1114,10 +1137,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc x, y, z, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId(biomeType)) + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) ); } } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java index 29d7278a5..721758c3e 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java @@ -59,7 +59,6 @@ import net.minecraft.world.level.entity.PersistentEntitySectionManager; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_20_R2.CraftChunk; -import sun.misc.Unsafe; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -99,7 +98,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingFluidCount; private static final Field fieldTickingBlockCount; - private static final Field fieldNonEmptyBlockCount; private static final MethodHandle methodGetVisibleChunk; @@ -108,6 +106,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodremoveTickingBlockEntity; + private static final Field fieldBiomes; /* * This is a workaround for the changes from https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/1fddefce1cdce44010927b888432bf70c0e88cde#src/main/java/org/bukkit/craftbukkit/CraftChunk.java @@ -143,8 +142,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount.setAccessible(true); - fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e")); - fieldNonEmptyBlockCount.setAccessible(true); + fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i")); + fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", @@ -408,7 +407,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @Nullable PalettedContainer> biomes ) { if (set == null) { - return newChunkSection(layer, biomeRegistry, biomes); + return newChunkSection(biomeRegistry, biomes); } final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); @@ -498,7 +497,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @SuppressWarnings("deprecation") // Only deprecated in paper private static LevelChunkSection newChunkSection( - int layer, Registry biomeRegistry, @Nullable PalettedContainer> biomes ) { @@ -513,6 +511,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return new LevelChunkSection(dataPaletteBlocks, biomes); } + public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer> biomes) { + try { + fieldBiomes.set(section, biomes); + } catch (IllegalAccessException e) { + LOGGER.error("Could not set biomes to chunk section", e); + } + } + /** * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. */ diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java index a52f7909f..2a4d1fec4 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java @@ -29,7 +29,11 @@ import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BlockTypesCache; import io.papermc.lib.PaperLib; import io.papermc.paper.event.block.BeaconDeactivatedEvent; -import net.minecraft.core.*; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.IdMap; +import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.nbt.IntTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; @@ -42,7 +46,14 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.entity.BeaconBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.*; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.HashMapPalette; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.LinearPalette; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.lighting.LevelLightEngine; import org.apache.logging.log4j.Logger; @@ -52,7 +63,17 @@ import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; import javax.annotation.Nonnull; -import java.util.*; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; @@ -496,7 +517,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } } } else { - setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); + PalettedContainer> paletteBiomes = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); + if (paletteBiomes != null) { + PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes); + } } } } @@ -538,11 +566,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (existingSection == null) { PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId( - BiomeTypes.PLAINS)), + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), PalettedContainer.Strategy.SECTION_BIOMES ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); newSection = PaperweightPlatformAdapter.newChunkSection( @@ -609,15 +633,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc existingSection.getBiomes() ); - newSection = - PaperweightPlatformAdapter.newChunkSection( - layerNo, - this::loadPrivately, - setArr, - adapter, - biomeRegistry, - biomeData - ); + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + this::loadPrivately, + setArr, + adapter, + biomeRegistry, + biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() + ); if (!PaperweightPlatformAdapter.setSectionAtomic( levelChunkSections, existingSection, @@ -829,7 +852,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (callback == null) { if (finalizer != null) { - finalizer.run(); + queueHandler.async(finalizer, null); } return null; } else { @@ -1084,9 +1107,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc final int sectionIndex, final PalettedContainerRO> data ) { + BiomeType[] sectionBiomes; + if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { + return null; + } PalettedContainer> biomeData; if (data instanceof PalettedContainer> palettedContainer) { - biomeData = palettedContainer; + biomeData = palettedContainer.copy(); } else { LOGGER.warn( "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + @@ -1096,10 +1123,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc ); biomeData = data.recreate(); } - BiomeType[] sectionBiomes; - if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { - return biomeData; - } for (int y = 0, index = 0; y < 4; y++) { for (int z = 0; z < 4; z++) { for (int x = 0; x < 4; x++, index++) { @@ -1111,10 +1134,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc x, y, z, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId(biomeType)) + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) ); } } diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java index 2f25bc6f1..fb655322b 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java @@ -98,7 +98,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingFluidCount; private static final Field fieldTickingBlockCount; - private static final Field fieldNonEmptyBlockCount; + private static final Field fieldBiomes; private static final MethodHandle methodGetVisibleChunk; @@ -142,8 +142,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount.setAccessible(true); - fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e")); - fieldNonEmptyBlockCount.setAccessible(true); + fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i")); + fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", @@ -407,7 +407,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @Nullable PalettedContainer> biomes ) { if (set == null) { - return newChunkSection(layer, biomeRegistry, biomes); + return newChunkSection(biomeRegistry, biomes); } final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); @@ -497,7 +497,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @SuppressWarnings("deprecation") // Only deprecated in paper private static LevelChunkSection newChunkSection( - int layer, Registry biomeRegistry, @Nullable PalettedContainer> biomes ) { @@ -512,6 +511,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return new LevelChunkSection(dataPaletteBlocks, biomes); } + public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer> biomes) { + try { + fieldBiomes.set(section, biomes); + } catch (IllegalAccessException e) { + LOGGER.error("Could not set biomes to chunk section", e); + } + } + /** * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. */ diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks.java index 2c0a46bb3..063829c0d 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks.java @@ -29,7 +29,11 @@ import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BlockTypesCache; import io.papermc.lib.PaperLib; import io.papermc.paper.event.block.BeaconDeactivatedEvent; -import net.minecraft.core.*; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.IdMap; +import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.nbt.IntTag; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ServerLevel; @@ -43,7 +47,14 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.entity.BeaconBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.*; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.HashMapPalette; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.LinearPalette; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.lighting.LevelLightEngine; import org.apache.logging.log4j.Logger; @@ -53,7 +64,17 @@ import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; import javax.annotation.Nonnull; -import java.util.*; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; @@ -499,7 +520,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } } } else { - setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); + PalettedContainer> paletteBiomes = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); + if (paletteBiomes != null) { + PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes); + } } } } @@ -541,11 +569,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (existingSection == null) { PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId( - BiomeTypes.PLAINS)), + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), PalettedContainer.Strategy.SECTION_BIOMES ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); newSection = PaperweightPlatformAdapter.newChunkSection( @@ -612,18 +636,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc existingSection.getBiomes() ); - newSection = - PaperweightPlatformAdapter.newChunkSection( - layerNo, - this::loadPrivately, - setArr, - adapter, - biomeRegistry, - biomeData - ); - if (!PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - existingSection, + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + this::loadPrivately, + setArr, + adapter, + biomeRegistry, + biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() + ); + if (!PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, existingSection, newSection, getSectionIndex )) { @@ -832,7 +853,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (callback == null) { if (finalizer != null) { - finalizer.run(); + queueHandler.async(finalizer, null); } return null; } else { @@ -1089,9 +1110,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc final int sectionIndex, final PalettedContainerRO> data ) { + BiomeType[] sectionBiomes; + if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { + return null; + } PalettedContainer> biomeData; if (data instanceof PalettedContainer> palettedContainer) { - biomeData = palettedContainer; + biomeData = palettedContainer.copy(); } else { LOGGER.warn( "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + @@ -1101,10 +1126,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc ); biomeData = data.recreate(); } - BiomeType[] sectionBiomes; - if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { - return biomeData; - } for (int y = 0, index = 0; y < 4; y++) { for (int z = 0; z < 4; z++) { for (int x = 0; x < 4; x++, index++) { @@ -1116,10 +1137,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc x, y, z, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId(biomeType)) + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) ); } } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java index 76a7a9025..6c0f72590 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java @@ -10,7 +10,6 @@ import com.fastasyncworldedit.core.math.BitArrayUnstretched; import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.ReflectionUtils; import com.fastasyncworldedit.core.util.TaskManager; -import com.mojang.datafixers.util.Either; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; @@ -77,7 +76,6 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -98,7 +96,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingFluidCount; private static final Field fieldTickingBlockCount; - private static final Field fieldNonEmptyBlockCount; + private static final Field fieldBiomes; private static final MethodHandle methodGetVisibleChunk; @@ -142,8 +140,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount.setAccessible(true); - fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e")); - fieldNonEmptyBlockCount.setAccessible(true); + fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i")); + fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", @@ -405,7 +403,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @Nullable PalettedContainer> biomes ) { if (set == null) { - return newChunkSection(layer, biomeRegistry, biomes); + return newChunkSection(biomeRegistry, biomes); } final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); @@ -495,7 +493,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @SuppressWarnings("deprecation") // Only deprecated in paper private static LevelChunkSection newChunkSection( - int layer, Registry biomeRegistry, @Nullable PalettedContainer> biomes ) { @@ -510,6 +507,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return new LevelChunkSection(dataPaletteBlocks, biomes); } + public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer> biomes) { + try { + fieldBiomes.set(section, biomes); + } catch (IllegalAccessException e) { + LOGGER.error("Could not set biomes to chunk section", e); + } + } + /** * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. */ From 3761b5184c8d25b6158e172c9491e50b067b5fc2 Mon Sep 17 00:00:00 2001 From: Jordan Date: Sat, 15 Jun 2024 15:52:11 +0200 Subject: [PATCH 281/466] fix: correctly create Minecraft Structure format schematics (#2787) - fixes #2784 - fixes #2785 --- .../io/schematic/MinecraftStructure.java | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java index c1f129112..91fb75495 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java @@ -19,7 +19,6 @@ import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.registry.state.AbstractProperty; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.block.BaseBlock; @@ -174,27 +173,23 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { ArrayList> palette = new ArrayList<>(); for (BlockVector3 point : region) { BlockState block = clipboard.getBlock(point); - int combined = block.getInternalId(); + char ordinal = block.getOrdinalChar(); BlockType type = block.getBlockType(); - if (type == BlockTypes.STRUCTURE_VOID || indexes.containsKey(combined)) { + if (type == BlockTypes.STRUCTURE_VOID || indexes.containsKey(ordinal)) { continue; } - indexes.put(combined, (Integer) palette.size()); + indexes.put(ordinal, palette.size()); HashMap paletteEntry = new HashMap<>(); paletteEntry.put("Name", type.id()); if (block.getInternalId() != type.getInternalId()) { Map properties = null; - for (AbstractProperty property : (List>) type.getProperties()) { - int propIndex = property.getIndex(block.getInternalId()); - if (propIndex != 0) { - if (properties == null) { - properties = new HashMap<>(); - } - Object value = property.getValues().get(propIndex); - properties.put(property.getName(), value.toString()); + for (Map.Entry, Object> entry : block.getStates().entrySet()) { + if (properties == null) { + properties = new HashMap<>(); } + properties.put(entry.getKey().getName(), entry.getValue().toString()); } if (properties != null) { paletteEntry.put("Properties", properties); @@ -211,16 +206,23 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { for (BlockVector3 point : region) { BaseBlock block = clipboard.getFullBlock(point); if (block.getBlockType() != BlockTypes.STRUCTURE_VOID) { - int combined = block.getInternalId(); - int index = indexes.get(combined); - List pos = Arrays.asList(point.x() - min.x(), - point.y() - min.y(), point.z() - min.z() + char ordinal = block.getOrdinalChar(); + int index = indexes.get(ordinal); + List pos = Arrays.asList( + point.x() - min.x(), + point.y() - min.y(), + point.z() - min.z() ); if (!block.hasNbtData()) { blocks.add(FaweCache.INSTANCE.asMap("state", index, "pos", pos)); } else { + Map tag = new HashMap<>(block.getNbtData().getValue()); + tag.remove("x"); + tag.remove("y"); + tag.remove("z"); + CompoundTag cTag = new CompoundTag(tag); blocks.add( - FaweCache.INSTANCE.asMap("state", index, "pos", pos, "nbt", block.getNbtData())); + FaweCache.INSTANCE.asMap("state", index, "pos", pos, "nbt", cTag)); } } } @@ -231,8 +233,16 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { ArrayList> entities = new ArrayList<>(); for (Entity entity : clipboard.getEntities()) { Location loc = entity.getLocation(); - List pos = Arrays.asList(loc.x(), loc.y(), loc.z()); - List blockPos = Arrays.asList(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + List pos = Arrays.asList( + loc.x() - min.x(), + loc.y() - min.y(), + loc.z() - min.z() + ); + List blockPos = Arrays.asList( + loc.getBlockX() - min.x(), + loc.getBlockY() - min.y(), + loc.getBlockZ() - min.z() + ); BaseEntity state = entity.getState(); if (state != null) { CompoundTag nbt = state.getNbtData(); From 49ac08d5b4e6b60dec435f0e768dad708eaa9c85 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sat, 15 Jun 2024 20:53:01 +0100 Subject: [PATCH 282/466] Revert "Remove self-refraction-check" This reverts commit 2eb6b5a12306cc2dc7cfc35e8c03f38ac8f7067c. --- .../impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java | 9 ++++++++- .../impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java | 9 ++++++++- .../impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java | 9 ++++++++- .../impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java | 9 ++++++++- .../impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java | 9 ++++++++- 5 files changed, 40 insertions(+), 5 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java index ccd6ed982..334289b08 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java @@ -139,7 +139,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g")); fieldTickingBlockCount.setAccessible(true); - fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "j")); + Field tmpFieldBiomes; + try { + // It seems to actually be biomes, but is apparently obfuscated to "j" + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); + } catch (NoSuchFieldException ignored) { + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("j"); + } + fieldBiomes = tmpFieldBiomes; fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java index 999dd3646..05c0b58f9 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java @@ -148,7 +148,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount.setAccessible(true); - fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i")); + Field tmpFieldBiomes; + try { + // It seems to actually be biomes, but is apparently obfuscated to "i" + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); + } catch (NoSuchFieldException ignored) { + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i"); + } + fieldBiomes = tmpFieldBiomes; fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java index 721758c3e..91dcfe24e 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java @@ -142,7 +142,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount.setAccessible(true); - fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i")); + Field tmpFieldBiomes; + try { + // It seems to actually be biomes, but is apparently obfuscated to "i" + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); + } catch (NoSuchFieldException ignored) { + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i"); + } + fieldBiomes = tmpFieldBiomes; fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java index fb655322b..f2f78eb7d 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java @@ -142,7 +142,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount.setAccessible(true); - fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i")); + Field tmpFieldBiomes; + try { + // It seems to actually be biomes, but is apparently obfuscated to "i" + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); + } catch (NoSuchFieldException ignored) { + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i"); + } + fieldBiomes = tmpFieldBiomes; fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java index 6c0f72590..e19e33524 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java @@ -140,7 +140,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount.setAccessible(true); - fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i")); + Field tmpFieldBiomes; + try { + // It seems to actually be biomes, but is apparently obfuscated to "i" + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); + } catch (NoSuchFieldException ignored) { + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i"); + } + fieldBiomes = tmpFieldBiomes; fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( From 5ab79a3f6156a7025a2d8b52e582781fb44b5af0 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sun, 16 Jun 2024 09:24:54 +0100 Subject: [PATCH 283/466] ref: biomes refrection works on 1.20.6 --- .../impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java index e19e33524..6c0f72590 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java @@ -140,14 +140,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount.setAccessible(true); - Field tmpFieldBiomes; - try { - // It seems to actually be biomes, but is apparently obfuscated to "i" - tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); - } catch (NoSuchFieldException ignored) { - tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i"); - } - fieldBiomes = tmpFieldBiomes; + fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i")); fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( From 7c7118ce26d471fa9b204b768fdd50a9fa9a2f52 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 01:44:06 +0000 Subject: [PATCH 284/466] Update dependency paperweight-userdev to v1.20.6-R0.1-20240615.211816-120 (#2794) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts index a2b5aa66d..4fca485af 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/ - the().paperDevBundle("1.20.6-R0.1-20240604.210637-112") + the().paperDevBundle("1.20.6-R0.1-20240615.211816-120") compileOnly(libs.paperlib) } From c7d6c907f187d374c2bc6444d5dc0a0a0ecbed26 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 01:44:30 +0000 Subject: [PATCH 285/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.3.0 (#2793) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bb46a654c..50e1a1757 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.2.14" +towny = "0.100.3.0" plotsquared = "7.3.8" # Third party From 6a54c5bcb53ee5a4b2b7dea832c413dd2bbea506 Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 17 Jun 2024 17:40:59 +0200 Subject: [PATCH 286/466] fix: recover from trimmed chunk (#2771) - It's theoretically possible for the section FULL to return a null layer due to race condition with a trim operation - Locally cache result and if null, recover - I just had the error from #1592 again - This seems to have stopped the error, but adding logging did not log, so possibly some bigger bytecode changes? - Oh well --- .../queue/implementation/blocks/CharBlocks.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java index 6eae2db5b..047394322 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java @@ -17,13 +17,23 @@ public abstract class CharBlocks implements IBlocks { protected static final Section FULL = new Section() { @Override public char[] get(CharBlocks blocks, int layer) { - return blocks.blocks[layer]; + char[] arr = blocks.blocks[layer]; + if (arr == null) { + // Chunk probably trimmed mid-operations, but do nothing about it to avoid other issues + return EMPTY.get(blocks, layer, false); + } + return arr; } // Ignore aggressive switch here. @Override public char[] get(CharBlocks blocks, int layer, boolean aggressive) { - return blocks.blocks[layer]; + char[] arr = blocks.blocks[layer]; + if (arr == null) { + // Chunk probably trimmed mid-operations, but do nothing about it to avoid other issues + return EMPTY.get(blocks, layer, false); + } + return arr; } @Override From eaeb3a633aa3a42c0824da33fe77fc995427c52d Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 19 Jun 2024 07:38:33 +0200 Subject: [PATCH 287/466] fix: always init ChunkFilterBlock to the chunk (#2788) - rename initFilterBlock from init to create - remove where we now needlessly init filter blocks - fixes #2662 --- .../core/queue/IQueueExtent.java | 14 +++++++++++--- .../queue/implementation/ParallelQueueExtent.java | 7 +++++-- .../implementation/SingleThreadQueueExtent.java | 2 +- .../core/regions/PolyhedralRegion.java | 2 +- .../fastasyncworldedit/core/regions/Triangle.java | 14 +++++++++++++- .../com/sk89q/worldedit/extent/MaskingExtent.java | 3 ++- .../com/sk89q/worldedit/regions/CuboidRegion.java | 1 - .../sk89q/worldedit/regions/EllipsoidRegion.java | 2 -- .../java/com/sk89q/worldedit/regions/Region.java | 1 - 9 files changed, 33 insertions(+), 13 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java index c13373d9a..3f104b35d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java @@ -115,7 +115,7 @@ public interface IQueueExtent extends Flushable, Trimable, ICh * A filter block is used to iterate over blocks / positions. Essentially combines BlockVector3, * Extent and BlockState functions in a way that avoids lookups. */ - ChunkFilterBlock initFilterBlock(); + ChunkFilterBlock createFilterBlock(); /** * Returns the number of chunks in this queue. @@ -129,7 +129,14 @@ public interface IQueueExtent extends Flushable, Trimable, ICh */ boolean isEmpty(); - default ChunkFilterBlock apply(ChunkFilterBlock block, Filter filter, Region region, int chunkX, int chunkZ, boolean full) { + default ChunkFilterBlock apply( + @Nullable ChunkFilterBlock block, + Filter filter, + Region region, + int chunkX, + int chunkZ, + boolean full + ) { if (!filter.appliesChunk(chunkX, chunkZ)) { return block; } @@ -139,8 +146,9 @@ public interface IQueueExtent extends Flushable, Trimable, ICh if (newChunk != null) { chunk = newChunk; if (block == null) { - block = this.initFilterBlock(); + block = this.createFilterBlock(); } + block.initChunk(chunkX, chunkZ); chunk.filterBlocks(filter, block, region, full); } this.submit(chunk); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java index 38546ed1b..1b56afdbc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java @@ -28,6 +28,7 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.world.World; @@ -133,14 +134,16 @@ public class ParallelQueueExtent extends PassthroughExtent { final int size = Math.min(chunks.size(), Settings.settings().QUEUE.PARALLEL_THREADS); if (size <= 1) { // if PQE is ever used with PARALLEL_THREADS = 1, or only one chunk is edited, just run sequentially + ChunkFilterBlock block = null; while (chunksIter.hasNext()) { BlockVector2 pos = chunksIter.next(); - getExtent().apply(null, filter, region, pos.x(), pos.z(), full); + block = getExtent().apply(block, filter, region, pos.x(), pos.z(), full); } } else { final ForkJoinTask[] tasks = IntStream.range(0, size).mapToObj(i -> handler.submit(() -> { try { final Filter newFilter = filter.fork(); + final Region newRegion = region.clone(); // Create a chunk that we will reuse/reset for each operation final SingleThreadQueueExtent queue = (SingleThreadQueueExtent) getNewQueue(); queue.setFastMode(fastmode); @@ -162,7 +165,7 @@ public class ParallelQueueExtent extends PassthroughExtent { chunkX = pos.x(); chunkZ = pos.z(); } - block = queue.apply(block, newFilter, region, chunkX, chunkZ, full); + block = queue.apply(block, newFilter, newRegion, chunkX, chunkZ, full); } queue.flush(); } catch (Throwable t) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java index 789547d83..b0239a5a3 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java @@ -473,7 +473,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen } @Override - public ChunkFilterBlock initFilterBlock() { + public ChunkFilterBlock createFilterBlock() { return new CharFilterBlock(this); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/PolyhedralRegion.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/PolyhedralRegion.java index dbfe840c8..a1471c9d8 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/PolyhedralRegion.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/PolyhedralRegion.java @@ -71,7 +71,7 @@ public class PolyhedralRegion extends AbstractRegion { public PolyhedralRegion(PolyhedralRegion region) { this(region.world); vertices.addAll(region.vertices); - triangles.addAll(region.triangles); + region.triangles.forEach(triangle -> triangles.add(triangle.clone())); vertexBacklog.addAll(region.vertexBacklog); minimumPoint = region.minimumPoint; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/Triangle.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/Triangle.java index 2bb9fc5ac..1d96d5f95 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/Triangle.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/Triangle.java @@ -7,10 +7,14 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.polyhedron.Edge; -public class Triangle { +public class Triangle implements Cloneable { public static double RADIUS = 0.5; + private final BlockVector3 pos1; + private final BlockVector3 pos2; + private final BlockVector3 pos3; + private final double[][] verts = new double[3][3]; private final double[] center = new double[3]; private final double[] radius = new double[3]; @@ -28,6 +32,9 @@ public class Triangle { private final double b; public Triangle(BlockVector3 pos1, BlockVector3 pos2, BlockVector3 pos3) { + this.pos1 = pos1; + this.pos2 = pos2; + this.pos3 = pos3; verts[0] = new double[]{pos1.x(), pos1.y(), pos1.z()}; verts[1] = new double[]{pos2.x(), pos2.y(), pos2.z()}; verts[2] = new double[]{pos3.x(), pos3.y(), pos3.z()}; @@ -290,4 +297,9 @@ public class Triangle { return dot(normal, vmax) >= 0.0f; } + @Override + public Triangle clone() { + return new Triangle(pos1, pos2, pos3); + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java index 64b6eecc3..0abc80153 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java @@ -106,7 +106,8 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce @Override public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) { final ChunkFilterBlock filter = getOrCreateFilterBlock.apply(Thread.currentThread().getId()); - return filter.filter(chunk, get, set, MaskingExtent.this); + filter.initChunk(chunk.getX(), chunk.getZ()); + return filter.filter(chunk, get, set, this); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index 8e4da9214..4b0894d91 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -755,7 +755,6 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { ) { int chunkX = chunk.getX(); int chunkZ = chunk.getZ(); - block = block.initChunk(chunkX, chunkZ); //Chunk entry is an "interior chunk" in regards to the entire region, so filter the chunk whole instead of partially if ((minX + 15) >> 4 <= chunkX && (maxX - 15) >> 4 >= chunkX && (minZ + 15) >> 4 <= chunkZ && (maxZ - 15) >> 4 >= chunkZ) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java index 944e7a14c..1bc13ed43 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java @@ -412,8 +412,6 @@ public class EllipsoidRegion extends AbstractRegion { return; } - block = block.initChunk(chunk.getX(), chunk.getZ()); - // Get the solid layers int cy = center.y(); int diffYFull = MathMan.usqrt(diffY2); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java index e8c6da179..08f2ee00c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java @@ -268,7 +268,6 @@ public interface Region extends Iterable, Cloneable, IBatchProcess ) { int minSection = Math.max(get.getMinSectionPosition(), getMinimumY() >> 4); int maxSection = Math.min(get.getMaxSectionPosition(), getMaximumY() >> 4); - block = block.initChunk(chunk.getX(), chunk.getZ()); for (int layer = minSection; layer <= maxSection; layer++) { if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { return; From d69dc979587a534334b86de1bfabeda16cc83a1a Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 20 Jun 2024 18:24:41 +0200 Subject: [PATCH 288/466] fix: take confirm-large from default limit for unlimited, add option to override (#2782) - fixes #2706 --- .../src/main/java/com/fastasyncworldedit/core/Fawe.java | 3 +++ .../com/fastasyncworldedit/core/configuration/Settings.java | 5 +++++ .../java/com/fastasyncworldedit/core/limit/FaweLimit.java | 4 +++- .../java/com/sk89q/worldedit/command/WorldEditCommands.java | 4 ++++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java index ff2f69486..829f29da6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java @@ -2,6 +2,7 @@ package com.fastasyncworldedit.core; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.internal.exception.FaweException; +import com.fastasyncworldedit.core.limit.FaweLimit; import com.fastasyncworldedit.core.queue.implementation.QueueHandler; import com.fastasyncworldedit.core.util.CachedTextureUtil; import com.fastasyncworldedit.core.util.CleanTextureUtil; @@ -105,6 +106,8 @@ public class Fawe { * Implementation dependent stuff */ this.setupConfigs(); + FaweLimit.MAX.CONFIRM_LARGE = + Settings.settings().LIMITS.get("default").CONFIRM_LARGE || Settings.settings().GENERAL.LIMIT_UNLIMITED_CONFIRMS; TaskManager.IMP = this.implementation.getTaskManager(); TaskManager.taskManager().async(() -> { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index cf0ba6f35..d069e62a1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -791,6 +791,11 @@ public class Settings extends Config { }) public boolean UNSTUCK_ON_GENERATE = true; + @Comment({ + "If unlimited limits should still require /confirm on large. Defaults to limits.default.confirm-large otherwise." + }) + public boolean LIMIT_UNLIMITED_CONFIRMS = true; + } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java index 5ecc89d44..e30ee4db6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java @@ -1,6 +1,7 @@ package com.fastasyncworldedit.core.limit; import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.configuration.Settings; import java.util.Collections; import java.util.Set; @@ -121,7 +122,8 @@ public class FaweLimit { MAX.SCHEM_FILE_SIZE_LIMIT = Integer.MAX_VALUE; MAX.MAX_EXPRESSION_MS = 50; MAX.FAST_PLACEMENT = true; - MAX.CONFIRM_LARGE = true; + MAX.CONFIRM_LARGE = + Settings.settings().LIMITS.get("default").CONFIRM_LARGE || Settings.settings().GENERAL.LIMIT_UNLIMITED_CONFIRMS; MAX.RESTRICT_HISTORY_TO_REGIONS = false; MAX.STRIP_NBT = Collections.emptySet(); MAX.UNIVERSAL_DISALLOWED_BLOCKS = false; 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 db611b75c..04274a79a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java @@ -22,6 +22,8 @@ package com.sk89q.worldedit.command; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.FaweVersion; import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.limit.FaweLimit; import com.fastasyncworldedit.core.util.UpdateNotification; import com.intellectualsites.paster.IncendoPaster; import com.sk89q.worldedit.LocalSession; @@ -97,6 +99,8 @@ public class WorldEditCommands { .getConfiguration())); //FAWE start Fawe.instance().setupConfigs(); + FaweLimit.MAX.CONFIRM_LARGE = + Settings.settings().LIMITS.get("default").CONFIRM_LARGE || Settings.settings().GENERAL.LIMIT_UNLIMITED_CONFIRMS; //FAWE end actor.print(Caption.of("worldedit.reload.config")); } From 705df34c12eac4e872a73e15e1ec97a0db2550df Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 20 Jun 2024 20:49:16 +0200 Subject: [PATCH 289/466] fix: create new biome paletted container when writing (#2791) - resizing a paletted container copy alters the original paletted container - copy is not clone - fixes #2790 --- .../fawe/v1_19_R3/PaperweightGetBlocks.java | 30 +++++++------------ .../v1_19_R3/PaperweightGetBlocks_Copy.java | 13 +++++--- .../fawe/v1_20_R1/PaperweightGetBlocks.java | 30 +++++++------------ .../v1_20_R1/PaperweightGetBlocks_Copy.java | 13 +++++--- .../fawe/v1_20_R2/PaperweightGetBlocks.java | 30 +++++++------------ .../v1_20_R2/PaperweightGetBlocks_Copy.java | 13 +++++--- .../fawe/v1_20_R3/PaperweightGetBlocks.java | 30 +++++++------------ .../v1_20_R3/PaperweightGetBlocks_Copy.java | 13 +++++--- .../fawe/v1_20_R4/PaperweightGetBlocks.java | 30 +++++++------------ .../v1_20_R4/PaperweightGetBlocks_Copy.java | 13 +++++--- 10 files changed, 95 insertions(+), 120 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java index 4d979fd0e..470378715 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java @@ -824,7 +824,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc nmsChunk.mustNotSave = false; nmsChunk.setUnsaved(true); // send to player - if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { + if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING || finalMask == 0 && biomes != null) { this.send(); } if (finalizer != null) { @@ -1109,31 +1109,21 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { return null; } - PalettedContainer> biomeData; - if (data instanceof PalettedContainer> palettedContainer) { - biomeData = palettedContainer.copy(); - } else { - LOGGER.warn( - "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + - "type {} but got {}", - PalettedContainer.class.getSimpleName(), - data.getClass().getSimpleName() - ); - biomeData = data.recreate(); - } + PalettedContainer> biomeData = data.recreate(); for (int y = 0, index = 0; y < 4; y++) { for (int z = 0; z < 4; z++) { for (int x = 0; x < 4; x++, index++) { BiomeType biomeType = sectionBiomes[index]; if (biomeType == null) { - continue; + biomeData.set(x, y, z, data.get(x, y, z)); + } else { + biomeData.set( + x, + y, + z, + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) + ); } - biomeData.set( - x, - y, - z, - biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) - ); } } } diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java index 7e908c74c..dd1787868 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java @@ -45,7 +45,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { private final int maxHeight; final ServerLevel serverLevel; final LevelChunk levelChunk; - private PalettedContainer>[] biomes = null; + private Holder[][] biomes = null; protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { this.levelChunk = levelChunk; @@ -144,7 +144,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { @Override public BiomeType getBiomeType(int x, int y, int z) { - Holder biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2); + Holder biome = biomes[(y >> 4) - getMinSectionPosition()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2]; return PaperweightPlatformAdapter.adapt(biome, serverLevel); } @@ -173,10 +173,15 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { protected void storeBiomes(int layer, PalettedContainerRO> biomeData) { if (biomes == null) { - biomes = new PalettedContainer[getSectionCount()]; + biomes = new Holder[getSectionCount()][]; + } + if (biomes[layer] == null) { + biomes[layer] = new Holder[64]; } if (biomeData instanceof PalettedContainer> palettedContainer) { - biomes[layer] = palettedContainer.copy(); + for (int i = 0; i < 64; i++) { + biomes[layer][i] = palettedContainer.get(i); + } } else { LOGGER.error( "Cannot correctly save biomes to history. Expected class type {} but got {}", diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java index cc329c16a..b26a42e74 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java @@ -822,7 +822,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc nmsChunk.mustNotSave = false; nmsChunk.setUnsaved(true); // send to player - if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { + if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING || finalMask == 0 && biomes != null) { this.send(); } if (finalizer != null) { @@ -1106,31 +1106,21 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { return null; } - PalettedContainer> biomeData; - if (data instanceof PalettedContainer> palettedContainer) { - biomeData = palettedContainer.copy(); - } else { - LOGGER.warn( - "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + - "type {} but got {}", - PalettedContainer.class.getSimpleName(), - data.getClass().getSimpleName() - ); - biomeData = data.recreate(); - } + PalettedContainer> biomeData = data.recreate(); for (int y = 0, index = 0; y < 4; y++) { for (int z = 0; z < 4; z++) { for (int x = 0; x < 4; x++, index++) { BiomeType biomeType = sectionBiomes[index]; if (biomeType == null) { - continue; + biomeData.set(x, y, z, data.get(x, y, z)); + } else { + biomeData.set( + x, + y, + z, + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) + ); } - biomeData.set( - x, - y, - z, - biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) - ); } } } diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java index a3ca91376..d2412b98f 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java @@ -45,7 +45,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { private final int maxHeight; final ServerLevel serverLevel; final LevelChunk levelChunk; - private PalettedContainer>[] biomes = null; + private Holder[][] biomes = null; protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { this.levelChunk = levelChunk; @@ -144,7 +144,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { @Override public BiomeType getBiomeType(int x, int y, int z) { - Holder biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2); + Holder biome = biomes[(y >> 4) - getMinSectionPosition()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2]; return PaperweightPlatformAdapter.adapt(biome, serverLevel); } @@ -173,10 +173,15 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { protected void storeBiomes(int layer, PalettedContainerRO> biomeData) { if (biomes == null) { - biomes = new PalettedContainer[getSectionCount()]; + biomes = new Holder[getSectionCount()][]; + } + if (biomes[layer] == null) { + biomes[layer] = new Holder[64]; } if (biomeData instanceof PalettedContainer> palettedContainer) { - biomes[layer] = palettedContainer.copy(); + for (int i = 0; i < 64; i++) { + biomes[layer][i] = palettedContainer.get(i); + } } else { LOGGER.error( "Cannot correctly save biomes to history. Expected class type {} but got {}", diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java index f5492fccb..58d53d037 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java @@ -830,7 +830,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc nmsChunk.mustNotSave = false; nmsChunk.setUnsaved(true); // send to player - if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { + if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING || finalMask == 0 && biomes != null) { this.send(); } if (finalizer != null) { @@ -1114,31 +1114,21 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { return null; } - PalettedContainer> biomeData; - if (data instanceof PalettedContainer> palettedContainer) { - biomeData = palettedContainer.copy(); - } else { - LOGGER.warn( - "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + - "type {} but got {}", - PalettedContainer.class.getSimpleName(), - data.getClass().getSimpleName() - ); - biomeData = data.recreate(); - } + PalettedContainer> biomeData = data.recreate(); for (int y = 0, index = 0; y < 4; y++) { for (int z = 0; z < 4; z++) { for (int x = 0; x < 4; x++, index++) { BiomeType biomeType = sectionBiomes[index]; if (biomeType == null) { - continue; + biomeData.set(x, y, z, data.get(x, y, z)); + } else { + biomeData.set( + x, + y, + z, + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) + ); } - biomeData.set( - x, - y, - z, - biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) - ); } } } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java index 1c1130764..b6f4c7d94 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java @@ -45,7 +45,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { private final int maxHeight; final ServerLevel serverLevel; final LevelChunk levelChunk; - private PalettedContainer>[] biomes = null; + private Holder[][] biomes = null; protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { this.levelChunk = levelChunk; @@ -144,7 +144,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { @Override public BiomeType getBiomeType(int x, int y, int z) { - Holder biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2); + Holder biome = biomes[(y >> 4) - getMinSectionPosition()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2]; return PaperweightPlatformAdapter.adapt(biome, serverLevel); } @@ -173,10 +173,15 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { protected void storeBiomes(int layer, PalettedContainerRO> biomeData) { if (biomes == null) { - biomes = new PalettedContainer[getSectionCount()]; + biomes = new Holder[getSectionCount()][]; + } + if (biomes[layer] == null) { + biomes[layer] = new Holder[64]; } if (biomeData instanceof PalettedContainer> palettedContainer) { - biomes[layer] = palettedContainer.copy(); + for (int i = 0; i < 64; i++) { + biomes[layer][i] = palettedContainer.get(i); + } } else { LOGGER.error( "Cannot correctly save biomes to history. Expected class type {} but got {}", diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java index 2a4d1fec4..afdd64baa 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java @@ -829,7 +829,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc nmsChunk.mustNotSave = false; nmsChunk.setUnsaved(true); // send to player - if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { + if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING || finalMask == 0 && biomes != null) { this.send(); } if (finalizer != null) { @@ -1111,31 +1111,21 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { return null; } - PalettedContainer> biomeData; - if (data instanceof PalettedContainer> palettedContainer) { - biomeData = palettedContainer.copy(); - } else { - LOGGER.warn( - "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + - "type {} but got {}", - PalettedContainer.class.getSimpleName(), - data.getClass().getSimpleName() - ); - biomeData = data.recreate(); - } + PalettedContainer> biomeData = data.recreate(); for (int y = 0, index = 0; y < 4; y++) { for (int z = 0; z < 4; z++) { for (int x = 0; x < 4; x++, index++) { BiomeType biomeType = sectionBiomes[index]; if (biomeType == null) { - continue; + biomeData.set(x, y, z, data.get(x, y, z)); + } else { + biomeData.set( + x, + y, + z, + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) + ); } - biomeData.set( - x, - y, - z, - biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) - ); } } } diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java index 92d9ec801..23c882284 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java @@ -45,7 +45,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { private final int maxHeight; final ServerLevel serverLevel; final LevelChunk levelChunk; - private PalettedContainer>[] biomes = null; + private Holder[][] biomes = null; protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { this.levelChunk = levelChunk; @@ -144,7 +144,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { @Override public BiomeType getBiomeType(int x, int y, int z) { - Holder biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2); + Holder biome = biomes[(y >> 4) - getMinSectionPosition()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2]; return PaperweightPlatformAdapter.adapt(biome, serverLevel); } @@ -173,10 +173,15 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { protected void storeBiomes(int layer, PalettedContainerRO> biomeData) { if (biomes == null) { - biomes = new PalettedContainer[getSectionCount()]; + biomes = new Holder[getSectionCount()][]; + } + if (biomes[layer] == null) { + biomes[layer] = new Holder[64]; } if (biomeData instanceof PalettedContainer> palettedContainer) { - biomes[layer] = palettedContainer.copy(); + for (int i = 0; i < 64; i++) { + biomes[layer][i] = palettedContainer.get(i); + } } else { LOGGER.error( "Cannot correctly save biomes to history. Expected class type {} but got {}", diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks.java index 063829c0d..bd2873b7f 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks.java @@ -830,7 +830,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc nmsChunk.mustNotSave = false; nmsChunk.setUnsaved(true); // send to player - if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { + if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING || finalMask == 0 && biomes != null) { this.send(); } if (finalizer != null) { @@ -1114,31 +1114,21 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { return null; } - PalettedContainer> biomeData; - if (data instanceof PalettedContainer> palettedContainer) { - biomeData = palettedContainer.copy(); - } else { - LOGGER.warn( - "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + - "type {} but got {}", - PalettedContainer.class.getSimpleName(), - data.getClass().getSimpleName() - ); - biomeData = data.recreate(); - } + PalettedContainer> biomeData = data.recreate(); for (int y = 0, index = 0; y < 4; y++) { for (int z = 0; z < 4; z++) { for (int x = 0; x < 4; x++, index++) { BiomeType biomeType = sectionBiomes[index]; if (biomeType == null) { - continue; + biomeData.set(x, y, z, data.get(x, y, z)); + } else { + biomeData.set( + x, + y, + z, + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) + ); } - biomeData.set( - x, - y, - z, - biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) - ); } } } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks_Copy.java index c0a7bda52..146760020 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks_Copy.java @@ -46,7 +46,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { private final int maxHeight; final ServerLevel serverLevel; final LevelChunk levelChunk; - private PalettedContainer>[] biomes = null; + private Holder[][] biomes = null; protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { this.levelChunk = levelChunk; @@ -145,7 +145,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { @Override public BiomeType getBiomeType(int x, int y, int z) { - Holder biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2); + Holder biome = biomes[(y >> 4) - getMinSectionPosition()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2]; return PaperweightPlatformAdapter.adapt(biome, serverLevel); } @@ -174,10 +174,15 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { protected void storeBiomes(int layer, PalettedContainerRO> biomeData) { if (biomes == null) { - biomes = new PalettedContainer[getSectionCount()]; + biomes = new Holder[getSectionCount()][]; + } + if (biomes[layer] == null) { + biomes[layer] = new Holder[64]; } if (biomeData instanceof PalettedContainer> palettedContainer) { - biomes[layer] = palettedContainer.copy(); + for (int i = 0; i < 64; i++) { + biomes[layer][i] = palettedContainer.get(i); + } } else { LOGGER.error( "Cannot correctly save biomes to history. Expected class type {} but got {}", From 4fe9c6bd7433117c9cade8be73925a404d7ba15b Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 21 Jun 2024 08:49:09 +0200 Subject: [PATCH 290/466] fix: correctly process chunks when using worldguard region blacklists (#2789) - fixes #2399 --- .../fastasyncworldedit/bukkit/regions/WorldGuardFeature.java | 4 ++++ .../src/main/java/com/sk89q/worldedit/regions/Region.java | 2 +- .../java/com/sk89q/worldedit/regions/RegionIntersection.java | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java index c847a8688..6a055de05 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java @@ -1,5 +1,6 @@ package com.fastasyncworldedit.bukkit.regions; +import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.regions.FaweMask; import com.fastasyncworldedit.core.regions.RegionWrapper; import com.sk89q.worldedit.bukkit.BukkitAdapter; @@ -158,6 +159,9 @@ public class WorldGuardFeature extends BukkitMaskManager implements Listener { @Override public FaweMask getMask(com.sk89q.worldedit.entity.Player wePlayer, MaskType type, boolean isWhitelist) { + if (isWhitelist && Settings.settings().REGION_RESTRICTIONS_OPTIONS.WORLDGUARD_REGION_BLACKLIST) { + return new FaweMask(RegionWrapper.GLOBAL()); + } final Player player = BukkitAdapter.adapt(wePlayer); final LocalPlayer localplayer = this.worldguard.wrapPlayer(player); final Location location = player.getLocation(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java index 08f2ee00c..085274772 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java @@ -482,7 +482,7 @@ public interface Region extends Iterable, Cloneable, IBatchProcess } return set; } else { - return null; + return set; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java index c1a81834c..4312e50fa 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java @@ -205,7 +205,7 @@ public class RegionIntersection extends AbstractRegion { BlockVector3 regMin = region.getMinimumPoint(); BlockVector3 regMax = region.getMaximumPoint(); if (tx >= regMin.x() && bx <= regMax.x() && tz >= regMin.z() && bz <= regMax.z()) { - return region.processSet(chunk, get, set, true); + set = region.processSet(chunk, get, set, true); } } return set; // default return set as no "blacklist" regions contained the chunk From 5708eb7aa0cdf46d0b0a538c7785d76518c139e0 Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 23 Jun 2024 22:33:36 +0200 Subject: [PATCH 291/466] fix: correct y index addition in biome history (#2797) --- .../core/history/changeset/FaweStreamChangeSet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java index 71232a31c..ad7c82c9f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java @@ -353,7 +353,7 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { os.write((byte) (z)); // only need to store biomes in the 4x4x4 chunks so only need one byte for y still (signed byte -128 -> 127) // means -512 -> 508. Add 128 to avoid negative value casting. - os.write((byte) (y + 32)); + os.write((byte) (y + 128)); os.writeVarInt(from.getInternalId()); os.writeVarInt(to.getInternalId()); } catch (IOException e) { From 3aa4a4b482293fc17b522414bb56e535269e3561 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2024 01:39:12 +0000 Subject: [PATCH 292/466] Update dependency paperweight-userdev to v1.20.6-R0.1-20240617.192752-122 (#2799) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts index 4fca485af..34e3569eb 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/ - the().paperDevBundle("1.20.6-R0.1-20240615.211816-120") + the().paperDevBundle("1.20.6-R0.1-20240617.192752-122") compileOnly(libs.paperlib) } From 06bf7104cc8867f81c0e2c4ca8e28f30303ea20c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2024 01:39:43 +0000 Subject: [PATCH 293/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.3.2 (#2798) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 50e1a1757..70a4116a6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.3.0" +towny = "0.100.3.2" plotsquared = "7.3.8" # Third party From 75af797d4c7462b445461cc96590ac0f59fd841c Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 26 Jun 2024 17:32:36 +0200 Subject: [PATCH 294/466] fix: extract new config option for deleting disk history on logout (#2772) * fix: extract new config option for deleting disk history on logout - fixes #2663 * Copyto is nullable --- .../core/configuration/Config.java | 78 +++++++++++++++---- .../core/configuration/Settings.java | 3 + .../com/sk89q/worldedit/entity/Player.java | 8 +- 3 files changed, 69 insertions(+), 20 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java index d230ab05b..2a1a5a5ef 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java @@ -6,6 +6,7 @@ import com.sk89q.util.StringUtil; import com.sk89q.worldedit.internal.util.LogManagerCompat; import org.apache.logging.log4j.Logger; +import javax.annotation.Nullable; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.PrintWriter; @@ -18,6 +19,7 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -31,10 +33,15 @@ public class Config { private static final Logger LOGGER = LogManagerCompat.getLogger(); private final Map removedKeyVals = new HashMap<>(); + @Nullable + private Map> copyTo = new HashMap<>(); + private boolean performCopyTo = false; private List existingMigrateNodes = null; public Config() { - save(new PrintWriter(new ByteArrayOutputStream(0)), getClass(), this, 0); + // This is now definitely required as the save -> load -> save order means the @CopiedFrom annotated fields work + save(new PrintWriter(new ByteArrayOutputStream(0)), getClass(), this, 0, null); + performCopyTo = true; } /** @@ -60,11 +67,12 @@ public class Config { /** * Set the value of a specific node. Probably throws some error if you supply non existing keys or invalid values. + * This should only be called during loading of a config file * * @param key config node * @param value value */ - private void set(String key, Object value, Class root) { + private void setLoadedNode(String key, Object value, Class root) { String[] split = key.split("\\."); Object instance = getInstance(split, root); if (instance != null) { @@ -74,8 +82,18 @@ public class Config { if (field.getAnnotation(Final.class) != null) { return; } + if (copyTo != null) { + copyTo.remove(key); // Remove if the config field is already written + final Object finalValue = value; + copyTo.replaceAll((copyToNode, entry) -> { + if (!key.equals(entry.getKey())) { + return entry; + } + return new AbstractMap.SimpleEntry<>(key, finalValue); + }); + } Migrate migrate = field.getAnnotation(Migrate.class); - if (existingMigrateNodes != null && migrate != null) { + if (migrate != null) { existingMigrateNodes.add(migrate.value()); } if (field.getType() == String.class && !(value instanceof String)) { @@ -90,8 +108,9 @@ public class Config { } } removedKeyVals.put(key, value); - LOGGER.error( - "Failed to set config option: {}: {} | {} | {}.yml. This is likely because it was removed.", + LOGGER.warn( + "Failed to set config option: {}: {} | {} | {}.yml. This is likely because it was removed or was set with an " + + "invalid value.", key, value, instance, @@ -110,7 +129,7 @@ public class Config { if (value instanceof MemorySection) { continue; } - set(key, value, getClass()); + setLoadedNode(key, value, getClass()); } for (String node : existingMigrateNodes) { removedKeyVals.remove(node); @@ -133,7 +152,7 @@ public class Config { } PrintWriter writer = new PrintWriter(file); Object instance = this; - save(writer, getClass(), instance, 0); + save(writer, getClass(), instance, 0, null); writer.close(); } catch (Throwable e) { LOGGER.error("Failed to save config file: {}", file, e); @@ -190,7 +209,7 @@ public class Config { } /** - * Indicates that a field should be instantiated / created. + * Indicates that a field should be migrated from a node that is deleted * * @since 2.10.0 */ @@ -202,6 +221,19 @@ public class Config { } + /** + * Indicates that a field's default value should match another input if the config is otherwise already generated + * + * @since TODO + */ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD}) + public @interface CopiedFrom { + + String value(); + + } + @Ignore // This is not part of the config public static class ConfigBlock { @@ -254,7 +286,7 @@ public class Config { return value != null ? value.toString() : "null"; } - private void save(PrintWriter writer, Class clazz, final Object instance, int indent) { + private void save(PrintWriter writer, Class clazz, final Object instance, int indent, String parentNode) { try { String CTRF = System.lineSeparator(); String spacing = StringMan.repeat(" ", indent); @@ -274,7 +306,7 @@ public class Config { } if (current == ConfigBlock.class) { current = (Class) ((ParameterizedType) (field.getGenericType())).getActualTypeArguments()[0]; - handleConfigBlockSave(writer, instance, indent, field, spacing, CTRF, current); + handleConfigBlockSave(writer, instance, indent, field, spacing, CTRF, current, parentNode); continue; } else if (!removedKeyVals.isEmpty()) { Migrate migrate = field.getAnnotation(Migrate.class); @@ -283,6 +315,17 @@ public class Config { field.set(instance, value); } } + CopiedFrom copiedFrom; + if (copyTo != null && (copiedFrom = field.getAnnotation(CopiedFrom.class)) != null) { + String node = toNodeName(field.getName()); + node = parentNode == null ? node : parentNode + "." + node; + Map.Entry entry = copyTo.remove(node); + if (entry == null) { + copyTo.put(node,new AbstractMap.SimpleEntry<>(copiedFrom.value(), null)); + } else { + field.set(instance, entry.getValue()); + } + } Create create = field.getAnnotation(Create.class); if (create != null) { Object value = field.get(instance); @@ -296,11 +339,12 @@ public class Config { writer.write(spacing + "# " + commentLine + CTRF); } } - writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF); + String node = toNodeName(current.getSimpleName()); + writer.write(spacing + node + ":" + CTRF); if (value == null) { field.set(instance, value = current.getDeclaredConstructor().newInstance()); } - save(writer, current, value, indent + 2); + save(writer, current, value, indent + 2, parentNode == null ? node : parentNode + "." + node); } else { writer.write(spacing + toNodeName(field.getName() + ": ") + toYamlString( field.get(instance), @@ -311,6 +355,10 @@ public class Config { } catch (Throwable e) { LOGGER.error("Failed to save config file", e); } + if (parentNode == null && performCopyTo) { + performCopyTo = false; + copyTo = null; + } } private void handleConfigBlockSave( @@ -320,7 +368,8 @@ public class Config { Field field, String spacing, String CTRF, - Class current + Class current, + String parentNode ) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException { Comment comment = current.getAnnotation(Comment.class); if (comment != null) { @@ -330,6 +379,7 @@ public class Config { } BlockName blockNames = current.getAnnotation(BlockName.class); if (blockNames != null) { + String node = toNodeName(current.getSimpleName()); writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF); ConfigBlock configBlock = (ConfigBlock) field.get(instance); if (configBlock == null || configBlock.getInstances().isEmpty()) { @@ -343,7 +393,7 @@ public class Config { for (Map.Entry entry : configBlock.getRaw().entrySet()) { String key = entry.getKey(); writer.write(spacing + " " + toNodeName(key) + ":" + CTRF); - save(writer, current, entry.getValue(), indent + 4); + save(writer, current, entry.getValue(), indent + 4, parentNode == null ? node : parentNode + "." + node); } } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index d069e62a1..5a10ad344 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -518,6 +518,9 @@ public class Settings extends Config { public int DELETE_AFTER_DAYS = 7; @Comment("Delete history in memory on logout (does not effect disk)") public boolean DELETE_ON_LOGOUT = true; + @Comment("Delete history on disk on logout") + @CopiedFrom("history.delete-on-logout") + public boolean DELETE_DISK_ON_LOGOUT = false; @Comment({ "If history should be enabled by default for plugins using WorldEdit:", " - It is faster to have disabled", 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 277d755b1..cc203190b 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 @@ -22,19 +22,15 @@ package com.sk89q.worldedit.entity; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.clipboard.DiskOptimizedClipboard; import com.fastasyncworldedit.core.internal.exception.FaweClipboardVersionMismatchException; import com.fastasyncworldedit.core.regions.FaweMaskManager; import com.fastasyncworldedit.core.util.MainUtil; -import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; -import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.internal.util.DeprecationUtil; @@ -43,7 +39,6 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionSelector; -import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; @@ -432,7 +427,8 @@ public interface Player extends Entity, Actor { } else if (Settings.settings().CLIPBOARD.DELETE_ON_LOGOUT) { session.setClipboard(null); } - if (Settings.settings().HISTORY.DELETE_ON_LOGOUT) { + if (!Settings.settings().HISTORY.USE_DISK && Settings.settings().HISTORY.DELETE_ON_LOGOUT + || Settings.settings().HISTORY.USE_DISK && Settings.settings().HISTORY.DELETE_DISK_ON_LOGOUT) { session.clearHistory(); } } From 6dd779f90bef02f2e23e8ed9b1f292e7a4d899d4 Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 26 Jun 2024 21:12:36 +0200 Subject: [PATCH 295/466] fix: only write copied value if non null (#2802) - fixes #2801 --- .../com/fastasyncworldedit/core/configuration/Config.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java index 2a1a5a5ef..1d6f8d146 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java @@ -320,10 +320,11 @@ public class Config { String node = toNodeName(field.getName()); node = parentNode == null ? node : parentNode + "." + node; Map.Entry entry = copyTo.remove(node); + Object copiedVal; if (entry == null) { - copyTo.put(node,new AbstractMap.SimpleEntry<>(copiedFrom.value(), null)); - } else { - field.set(instance, entry.getValue()); + copyTo.put(node, new AbstractMap.SimpleEntry<>(copiedFrom.value(), null)); + } else if ((copiedVal = entry.getValue()) != null) { + field.set(instance, copiedVal); } } Create create = field.getAnnotation(Create.class); From ad5739e014e26dd0f6308ce270762783107eec88 Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 26 Jun 2024 21:55:47 +0200 Subject: [PATCH 296/466] ref: switch from adventure NBT to LinBus (#2778) * Switch from adventure NBT to LinBus * Cleanup * Clean * Reimplement NumberTag behaviour * Use 0.1.0 release * Fix build, remove fawe tags --------- Co-authored-by: Octavia Togami --- buildSrc/src/main/kotlin/LibsConfig.kt | 30 ++- gradle/libs.versions.toml | 7 +- .../ext/fawe/v1_19_R3/PaperweightAdapter.java | 157 +++++------ .../v1_19_R3/PaperweightDataConverters.java | 30 +-- .../PaperweightWorldNativeAccess.java | 18 +- .../fawe/v1_19_R3/PaperweightFaweAdapter.java | 20 +- .../PaperweightFaweWorldNativeAccess.java | 6 +- .../fawe/v1_19_R3/PaperweightGetBlocks.java | 2 +- .../nbt/PaperweightLazyCompoundTag.java | 14 +- .../ext/fawe/v1_20_R1/PaperweightAdapter.java | 155 +++++------ .../v1_20_R1/PaperweightDataConverters.java | 30 +-- .../PaperweightWorldNativeAccess.java | 18 +- .../fawe/v1_20_R1/PaperweightFaweAdapter.java | 20 +- .../PaperweightFaweWorldNativeAccess.java | 9 +- .../fawe/v1_20_R1/PaperweightGetBlocks.java | 2 +- .../nbt/PaperweightLazyCompoundTag.java | 14 +- .../ext/fawe/v1_20_R2/PaperweightAdapter.java | 151 +++++------ .../v1_20_R2/PaperweightDataConverters.java | 30 +-- .../PaperweightWorldNativeAccess.java | 6 +- .../fawe/v1_20_R2/PaperweightFaweAdapter.java | 20 +- .../PaperweightFaweWorldNativeAccess.java | 9 +- .../fawe/v1_20_R2/PaperweightGetBlocks.java | 2 +- .../nbt/PaperweightLazyCompoundTag.java | 14 +- .../ext.fawe/v1_20_R3/PaperweightAdapter.java | 151 +++++------ .../v1_20_R3/PaperweightDataConverters.java | 31 +-- .../PaperweightWorldNativeAccess.java | 18 +- .../fawe/v1_20_R3/PaperweightFaweAdapter.java | 20 +- .../PaperweightFaweWorldNativeAccess.java | 8 +- .../fawe/v1_20_R3/PaperweightGetBlocks.java | 2 +- .../nbt/PaperweightLazyCompoundTag.java | 14 +- .../ext.fawe/v1_20_R4/PaperweightAdapter.java | 153 +++++------ .../v1_20_R4/PaperweightDataConverters.java | 31 +-- .../PaperweightWorldNativeAccess.java | 6 +- .../fawe/v1_20_R4/PaperweightFaweAdapter.java | 20 +- .../PaperweightFaweWorldNativeAccess.java | 8 +- .../fawe/v1_20_R4/PaperweightGetBlocks.java | 2 +- .../nbt/PaperweightLazyCompoundTag.java | 14 +- worldedit-bukkit/build.gradle.kts | 3 - .../adapter/IDelegateBukkitImplAdapter.java | 15 +- .../FaweDelegateSchematicHandler.java | 4 +- .../sk89q/worldedit/bukkit/BukkitPlayer.java | 4 +- .../bukkit/adapter/BukkitImplAdapter.java | 20 +- worldedit-core/build.gradle.kts | 3 +- .../worldedit/blocks/MobSpawnerBlock.java | 4 +- .../com/sk89q/worldedit/blocks/SignBlock.java | 8 +- .../sk89q/worldedit/blocks/SkullBlock.java | 6 +- .../fastasyncworldedit/core/FaweCache.java | 2 +- .../core/entity/LazyBaseEntity.java | 10 +- .../core/extent/StripNBTExtent.java | 10 +- .../clipboard/CPUOptimizedClipboard.java | 4 +- .../clipboard/DiskOptimizedClipboard.java | 4 +- .../extent/clipboard/LinearClipboard.java | 2 +- .../clipboard/MemoryOptimizedClipboard.java | 2 +- .../clipboard/io/FastSchematicReader.java | 18 +- .../clipboard/io/FastSchematicWriter.java | 4 +- .../io/schematic/MinecraftStructure.java | 14 +- .../history/change/MutableEntityChange.java | 5 +- .../history/changeset/BlockBagChangeSet.java | 2 +- .../core/jnbt/CompressedCompoundTag.java | 6 +- .../core/jnbt/JSON2NBT.java | 3 +- .../core/jnbt/NumberTag.java | 7 +- .../core/queue/IChunkExtent.java | 2 +- .../core/util/BrushCache.java | 5 +- .../core/util/MainUtil.java | 4 +- .../core/util/NbtUtils.java | 45 ++-- .../core/util/gson/BaseItemAdapter.java | 16 +- .../com/sk89q/jnbt/AdventureNBTConverter.java | 110 -------- .../java/com/sk89q/jnbt/ByteArrayTag.java | 27 +- .../src/main/java/com/sk89q/jnbt/ByteTag.java | 25 +- .../main/java/com/sk89q/jnbt/CompoundTag.java | 124 +++++---- .../com/sk89q/jnbt/CompoundTagBuilder.java | 22 +- .../main/java/com/sk89q/jnbt/DoubleTag.java | 23 +- .../src/main/java/com/sk89q/jnbt/EndTag.java | 17 +- .../main/java/com/sk89q/jnbt/FloatTag.java | 24 +- .../main/java/com/sk89q/jnbt/IntArrayTag.java | 25 +- .../src/main/java/com/sk89q/jnbt/IntTag.java | 24 +- .../java/com/sk89q/jnbt/LazyCompoundTag.java | 10 +- .../java/com/sk89q/jnbt/LinBusConverter.java | 140 ++++++++++ .../src/main/java/com/sk89q/jnbt/ListTag.java | 193 ++++++-------- .../java/com/sk89q/jnbt/ListTagBuilder.java | 52 ++-- .../java/com/sk89q/jnbt/LongArrayTag.java | 25 +- .../src/main/java/com/sk89q/jnbt/LongTag.java | 25 +- .../java/com/sk89q/jnbt/NBTConstants.java | 53 ++-- .../java/com/sk89q/jnbt/NBTInputStream.java | 7 +- .../java/com/sk89q/jnbt/NBTOutputStream.java | 18 +- .../main/java/com/sk89q/jnbt/NBTUtils.java | 80 +++--- .../main/java/com/sk89q/jnbt/NamedTag.java | 6 +- .../main/java/com/sk89q/jnbt/ShortTag.java | 25 +- .../main/java/com/sk89q/jnbt/StringTag.java | 25 +- .../src/main/java/com/sk89q/jnbt/Tag.java | 29 +- .../com/sk89q/worldedit/LocalSession.java | 13 +- .../com/sk89q/worldedit/blocks/BaseItem.java | 67 ++--- .../sk89q/worldedit/blocks/BaseItemStack.java | 28 +- .../sk89q/worldedit/entity/BaseEntity.java | 10 +- .../factory/parser/DefaultItemParser.java | 24 +- .../extent/clipboard/BlockArrayClipboard.java | 2 +- .../clipboard/io/BuiltInClipboardFormat.java | 2 +- .../clipboard/io/MCEditSchematicReader.java | 230 ++++++---------- .../clipboard/io/NBTSchematicReader.java | 8 +- .../clipboard/io/SpongeSchematicReader.java | 49 ++-- .../clipboard/io/SpongeSchematicWriter.java | 18 +- .../BannerBlockCompatibilityHandler.java | 142 ++++------ .../BedBlockCompatibilityHandler.java | 144 ++++------ .../EntityNBTCompatibilityHandler.java | 40 ++- .../FlowerPotCompatibilityHandler.java | 79 +++--- .../legacycompat/NBTCompatibilityHandler.java | 69 ++++- .../NoteBlockCompatibilityHandler.java | 37 ++- .../Pre13HangingCompatibilityHandler.java | 34 +-- .../SignCompatibilityHandler.java | 74 +++--- .../SkullBlockCompatibilityHandler.java | 112 ++++---- .../transform/BlockTransformExtent.java | 2 +- .../extent/world/SurvivalModeExtent.java | 6 +- .../function/block/ExtentBlockCopy.java | 19 +- .../internal/cui/ServerCUIHandler.java | 7 +- .../internal/wna/WorldNativeAccess.java | 25 +- .../com/sk89q/worldedit/world/DataFixer.java | 18 +- .../com/sk89q/worldedit/world/NbtValued.java | 20 +- .../worldedit/world/block/BaseBlock.java | 37 ++- .../worldedit/world/block/BlockState.java | 4 +- .../world/block/BlockStateHolder.java | 9 +- .../worldedit/world/chunk/AnvilChunk.java | 130 ++++----- .../worldedit/world/chunk/AnvilChunk13.java | 161 ++++++----- .../worldedit/world/chunk/AnvilChunk15.java | 15 +- .../worldedit/world/chunk/AnvilChunk16.java | 6 +- .../worldedit/world/chunk/AnvilChunk17.java | 121 ++++----- .../worldedit/world/chunk/AnvilChunk18.java | 251 ++++-------------- .../sk89q/worldedit/world/chunk/OldChunk.java | 87 +++--- .../world/snapshot/SnapshotRestore.java | 23 +- .../experimental/SnapshotRestore.java | 24 +- .../world/storage/ChunkStoreHelper.java | 20 +- .../world/storage/NBTConversions.java | 35 ++- .../fabric/internal/NBTConverter.java | 4 +- .../forge/internal/NBTConverter.java | 4 +- worldedit-libs/core/build.gradle.kts | 7 +- 134 files changed, 2258 insertions(+), 2542 deletions(-) delete mode 100644 worldedit-core/src/main/java/com/sk89q/jnbt/AdventureNBTConverter.java create mode 100644 worldedit-core/src/main/java/com/sk89q/jnbt/LinBusConverter.java diff --git a/buildSrc/src/main/kotlin/LibsConfig.kt b/buildSrc/src/main/kotlin/LibsConfig.kt index 2c957880a..4bf9ffca2 100644 --- a/buildSrc/src/main/kotlin/LibsConfig.kt +++ b/buildSrc/src/main/kotlin/LibsConfig.kt @@ -40,8 +40,7 @@ fun Project.applyLibrariesConfiguration() { val relocations = mapOf( "net.kyori.text" to "com.sk89q.worldedit.util.formatting.text", - "net.kyori.minecraft" to "com.sk89q.worldedit.util.kyori", - "net.kyori.adventure.nbt" to "com.sk89q.worldedit.util.nbt" + "net.kyori.minecraft" to "com.sk89q.worldedit.util.kyori" ) @@ -53,9 +52,14 @@ fun Project.applyLibrariesConfiguration() { exclude(dependency("com.google.guava:guava")) exclude(dependency("com.google.code.gson:gson")) exclude(dependency("com.google.errorprone:error_prone_annotations")) + exclude(dependency("com.google.guava:failureaccess")) exclude(dependency("org.checkerframework:checker-qual")) + exclude(dependency("org.jetbrains:annotations")) exclude(dependency("org.apache.logging.log4j:log4j-api")) exclude(dependency("com.google.code.findbugs:jsr305")) + exclude { + it.moduleGroup == "org.jetbrains.kotlin" + } } relocations.forEach { (from, to) -> @@ -67,11 +71,19 @@ fun Project.applyLibrariesConfiguration() { .filterIsInstance() .map { it.copy() } .map { dependency -> - dependency.artifact { - name = dependency.name - type = artifactType - extension = "jar" - classifier = artifactType + val category = dependency.attributes.getAttribute(Category.CATEGORY_ATTRIBUTE)?.name + if (category == Category.REGULAR_PLATFORM || category == Category.ENFORCED_PLATFORM) { + return@map dependency + } + try { + dependency.artifact { + name = dependency.name + type = artifactType + extension = "jar" + classifier = artifactType + } + } catch (e: Exception) { + throw RuntimeException("Failed to add artifact to dependency: $dependency", e) } dependency } @@ -85,6 +97,10 @@ fun Project.applyLibrariesConfiguration() { from({ altConfigFiles("sources") }) + + // Yeet module-info's + exclude("module-info.java") + relocations.forEach { (from, to) -> val filePattern = Regex("(.*)${from.replace('.', '/')}((?:/|$).*)") val textPattern = Regex.fromLiteral(from) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 70a4116a6..4f64aa273 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -40,6 +40,7 @@ paperlib = "1.0.8" paster = "1.1.6" vault = "1.7.1" serverlib = "2.3.6" +linbus = "0.1.0" ## Internal text-adapter = "3.0.6" text = "3.0.4" @@ -78,7 +79,6 @@ bstatsBase = { group = "org.bstats", name = "bstats-base", version.ref = "bstats bstatsBukkit = { group = "org.bstats", name = "bstats-bukkit", version.ref = "bstats" } sparsebitset = { group = "com.zaxxer", name = "SparseBitSet", version.ref = "sparsebitset" } parallelgzip = { group = "org.anarres", name = "parallelgzip", version.ref = "parallelgzip" } -adventureNbt = { group = "net.kyori", name = "adventure-nbt", version.ref = "adventure" } truezip = { group = "de.schlichtherle", name = "truezip", version.ref = "truezip" } autoValueAnnotations = { group = "com.google.auto.value", name = "auto-value-annotations", version.ref = "auto-value" } autoValue = { group = "com.google.auto.value", name = "auto-value", version.ref = "auto-value" } @@ -101,6 +101,11 @@ paster = { group = "com.intellectualsites.paster", name = "Paster", version.ref vault = { group = "com.github.MilkBowl", name = "VaultAPI", version.ref = "vault" } serverlib = { group = "dev.notmyfault.serverlib", name = "ServerLib", version.ref = "serverlib" } checkerqual = { group = "org.checkerframework", name = "checker-qual", version.ref = "checkerqual" } +linBus-bom = { group = "org.enginehub.lin-bus", name = "lin-bus-bom", version.ref = "linbus" } +linBus-common = { group = "org.enginehub.lin-bus", name = "lin-bus-common" } +linBus-stream = { group = "org.enginehub.lin-bus", name = "lin-bus-stream" } +linBus-tree = { group = "org.enginehub.lin-bus", name = "lin-bus-tree" } +linBus-format-snbt = { group = "org.enginehub.lin-bus.format", name = "lin-bus-format-snbt" } # Internal ## Text diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java index fa027e567..a5c3da0e1 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java @@ -55,20 +55,6 @@ import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.ByteBinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; -import com.sk89q.worldedit.util.nbt.EndBinaryTag; -import com.sk89q.worldedit.util.nbt.FloatBinaryTag; -import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; -import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.LongBinaryTag; -import com.sk89q.worldedit.util.nbt.ShortBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.biome.BiomeType; @@ -134,9 +120,26 @@ import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.generator.ChunkGenerator; +import org.enginehub.linbus.common.LinTagId; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinByteTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinEndTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinLongArrayTag; +import org.enginehub.linbus.tree.LinLongTag; +import org.enginehub.linbus.tree.LinShortTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import org.spigotmc.SpigotConfig; import org.spigotmc.WatchdogThread; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -158,14 +161,13 @@ import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; -import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; public final class PaperweightAdapter implements BukkitImplAdapter { - private final Logger LOGGER = Logger.getLogger(getClass().getCanonicalName()); + private final Logger logger = Logger.getLogger(getClass().getCanonicalName()); private final Field serverWorldsField; private final Method getChunkFutureMethod; @@ -347,7 +349,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter (CompoundBinaryTag) toNativeBinary(tag)) + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) ); } @@ -443,9 +445,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) + __ -> (net.minecraft.nbt.CompoundTag) fromNativeLin(nbtData) )); } @@ -558,7 +560,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLin(net.minecraft.nbt.Tag foreign) { if (foreign == null) { return null; } if (foreign instanceof net.minecraft.nbt.CompoundTag) { - Map values = new HashMap<>(); + Map> values = new HashMap<>(); Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); for (String str : foreignKeys) { net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); - values.put(str, toNativeBinary(base)); + values.put(str, toNativeLin(base)); } - return CompoundBinaryTag.from(values); + return LinCompoundTag.of(values); } else if (foreign instanceof net.minecraft.nbt.ByteTag) { - return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); + return LinByteTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { - return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); + return LinByteArrayTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { - return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); + return LinDoubleTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); } else if (foreign instanceof net.minecraft.nbt.FloatTag) { - return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); + return LinFloatTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); } else if (foreign instanceof net.minecraft.nbt.IntTag) { - return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); + return LinIntTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { - return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); + return LinIntArrayTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { - return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); + return LinLongArrayTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); } else if (foreign instanceof net.minecraft.nbt.ListTag) { try { - return toNativeList((net.minecraft.nbt.ListTag) foreign); + return toNativeLinList((net.minecraft.nbt.ListTag) foreign); } catch (Throwable e) { - LOGGER.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); - return ListBinaryTag.empty(); + logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); } } else if (foreign instanceof net.minecraft.nbt.LongTag) { - return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); + return LinLongTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); } else if (foreign instanceof net.minecraft.nbt.ShortTag) { - return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); + return LinShortTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); } else if (foreign instanceof net.minecraft.nbt.StringTag) { - return StringBinaryTag.of(foreign.getAsString()); + return LinStringTag.of(foreign.getAsString()); } else if (foreign instanceof net.minecraft.nbt.EndTag) { - return EndBinaryTag.get(); - } else { - throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); + return LinEndTag.instance(); } + throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); } /** @@ -871,14 +871,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLinList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { + LinListTag.Builder> builder = LinListTag.builder( + LinTagType.fromId(LinTagId.fromId(foreign.getElementType())) + ); for (net.minecraft.nbt.Tag tag : foreign) { - values.add(toNativeBinary(tag)); + builder.add(toNativeLin(tag)); } - return values.build(); + return builder.build(); } /** @@ -888,44 +890,43 @@ public final class PaperweightAdapter implements BukkitImplAdapter foreign) { if (foreign == null) { return null; } - if (foreign instanceof CompoundBinaryTag) { + if (foreign instanceof LinCompoundTag compoundTag) { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - for (String key : ((CompoundBinaryTag) foreign).keySet()) { - tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); + for (var entry : compoundTag.value().entrySet()) { + tag.put(entry.getKey(), fromNativeLin(entry.getValue())); } return tag; - } else if (foreign instanceof ByteBinaryTag) { - return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); - } else if (foreign instanceof ByteArrayBinaryTag) { - return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); - } else if (foreign instanceof DoubleBinaryTag) { - return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); - } else if (foreign instanceof FloatBinaryTag) { - return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); - } else if (foreign instanceof IntBinaryTag) { - return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); - } else if (foreign instanceof IntArrayBinaryTag) { - return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); - } else if (foreign instanceof LongArrayBinaryTag) { - return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); - } else if (foreign instanceof ListBinaryTag) { + } else if (foreign instanceof LinByteTag byteTag) { + return net.minecraft.nbt.ByteTag.valueOf(byteTag.valueAsByte()); + } else if (foreign instanceof LinByteArrayTag byteArrayTag) { + return new net.minecraft.nbt.ByteArrayTag(byteArrayTag.value()); + } else if (foreign instanceof LinDoubleTag doubleTag) { + return net.minecraft.nbt.DoubleTag.valueOf(doubleTag.valueAsDouble()); + } else if (foreign instanceof LinFloatTag floatTag) { + return net.minecraft.nbt.FloatTag.valueOf(floatTag.valueAsFloat()); + } else if (foreign instanceof LinIntTag intTag) { + return net.minecraft.nbt.IntTag.valueOf(intTag.valueAsInt()); + } else if (foreign instanceof LinIntArrayTag intArrayTag) { + return new net.minecraft.nbt.IntArrayTag(intArrayTag.value()); + } else if (foreign instanceof LinLongArrayTag longArrayTag) { + return new net.minecraft.nbt.LongArrayTag(longArrayTag.value()); + } else if (foreign instanceof LinListTag listTag) { net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); - ListBinaryTag foreignList = (ListBinaryTag) foreign; - for (BinaryTag t : foreignList) { - tag.add(fromNativeBinary(t)); + for (var t : listTag.value()) { + tag.add(fromNativeLin(t)); } return tag; - } else if (foreign instanceof LongBinaryTag) { - return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); - } else if (foreign instanceof ShortBinaryTag) { - return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); - } else if (foreign instanceof StringBinaryTag) { - return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); - } else if (foreign instanceof EndBinaryTag) { + } else if (foreign instanceof LinLongTag longTag) { + return net.minecraft.nbt.LongTag.valueOf(longTag.valueAsLong()); + } else if (foreign instanceof LinShortTag shortTag) { + return net.minecraft.nbt.ShortTag.valueOf(shortTag.valueAsShort()); + } else if (foreign instanceof LinStringTag stringTag) { + return net.minecraft.nbt.StringTag.valueOf(stringTag.value()); + } else if (foreign instanceof LinEndTag) { return net.minecraft.nbt.EndTag.INSTANCE; } else { throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); @@ -964,7 +965,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter T fixUp(FixType type, T original, int srcVer) { if (type == FixTypes.CHUNK) { - return (T) fixChunk((CompoundBinaryTag) original, srcVer); + return (T) fixChunk((LinCompoundTag) original, srcVer); } else if (type == FixTypes.BLOCK_ENTITY) { - return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); + return (T) fixBlockEntity((LinCompoundTag) original, srcVer); } else if (type == FixTypes.ENTITY) { - return (T) fixEntity((CompoundBinaryTag) original, srcVer); + return (T) fixEntity((LinCompoundTag) original, srcVer); } else if (type == FixTypes.BLOCK_STATE) { return (T) fixBlockState((String) original, srcVer); } else if (type == FixTypes.ITEM_TYPE) { @@ -98,24 +97,23 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return original; } - private CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); + private LinCompoundTag fixChunk(LinCompoundTag originalChunk, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(originalChunk); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); + private LinCompoundTag fixBlockEntity(LinCompoundTag origTileEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origTileEnt); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); + private LinCompoundTag fixEntity(LinCompoundTag origEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origEnt); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - //FAWE end private String fixBlockState(String blockState, int srcVer) { net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState); diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightWorldNativeAccess.java index 22d9f917b..7923c9e69 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightWorldNativeAccess.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightWorldNativeAccess.java @@ -19,25 +19,28 @@ package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R3; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.block.BlockState; import net.minecraft.core.BlockPos; +import net.minecraft.nbt.Tag; import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.chunk.LevelChunk; import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; import org.bukkit.event.block.BlockPhysicsEvent; +import org.enginehub.linbus.tree.LinCompoundTag; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.util.Objects; -import javax.annotation.Nullable; public class PaperweightWorldNativeAccess implements WorldNativeAccess { private static final int UPDATE = 1; @@ -101,8 +104,15 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess saveTag = () -> { + Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); PaperweightPlatformAdapter.readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work - final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); - final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); - tags.put("Id", StringBinaryTag.of(id)); - return CompoundBinaryTag.from(tags); + final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag); + final Map> tags = NbtUtils.getLinCompoundTagValues(tag); + tags.put("Id", LinStringTag.of(id)); + return LinCompoundTag.of(tags); }; return new LazyBaseEntity(type, saveTag); } else { @@ -514,7 +514,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter iterator = entities.iterator(); while (iterator.hasNext()) { final CompoundTag nativeTag = iterator.next(); - final Map entityTagMap = nativeTag.getValue(); + final Map> entityTagMap = nativeTag.getValue(); final StringTag idTag = (StringTag) entityTagMap.get("Id"); final ListTag posTag = (ListTag) entityTagMap.get("Pos"); final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/nbt/PaperweightLazyCompoundTag.java index 7db487c3f..0026c4c67 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/nbt/PaperweightLazyCompoundTag.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/nbt/PaperweightLazyCompoundTag.java @@ -6,8 +6,8 @@ import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import net.minecraft.nbt.NumericTag; +import org.enginehub.linbus.tree.LinCompoundTag; import java.util.ArrayList; import java.util.Collections; @@ -36,7 +36,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { @Override @SuppressWarnings("unchecked") - public Map getValue() { + public Map> getValue() { if (compoundTag == null) { compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); } @@ -44,9 +44,9 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @Override - public CompoundBinaryTag asBinaryTag() { + public LinCompoundTag toLinTag() { getValue(); - return compoundTag.asBinaryTag(); + return compoundTag.toLinTag(); } public boolean containsKey(String key) { @@ -94,10 +94,10 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key) { + public List> getList(String key) { net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); if (tag instanceof net.minecraft.nbt.ListTag nbtList) { - ArrayList list = new ArrayList<>(); + ArrayList> list = new ArrayList<>(); for (net.minecraft.nbt.Tag elem : nbtList) { if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { list.add(new PaperweightLazyCompoundTag(compoundTag)); @@ -120,7 +120,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key, Class listType) { + public > List getList(String key, Class listType) { ListTag listTag = getListTag(key); if (listTag.getType().equals(listType)) { return (List) listTag.getValue(); diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java index 519620061..f0ba19c6d 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java @@ -55,20 +55,6 @@ import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.ByteBinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; -import com.sk89q.worldedit.util.nbt.EndBinaryTag; -import com.sk89q.worldedit.util.nbt.FloatBinaryTag; -import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; -import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.LongBinaryTag; -import com.sk89q.worldedit.util.nbt.ShortBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.biome.BiomeType; @@ -135,6 +121,22 @@ import org.bukkit.craftbukkit.v1_20_R1.util.CraftMagicNumbers; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.generator.ChunkGenerator; +import org.enginehub.linbus.common.LinTagId; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinByteTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinEndTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinLongArrayTag; +import org.enginehub.linbus.tree.LinLongTag; +import org.enginehub.linbus.tree.LinShortTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import org.spigotmc.SpigotConfig; import org.spigotmc.WatchdogThread; @@ -166,7 +168,7 @@ import static com.google.common.base.Preconditions.checkState; public final class PaperweightAdapter implements BukkitImplAdapter { - private final Logger LOGGER = Logger.getLogger(getClass().getCanonicalName()); + private final Logger logger = Logger.getLogger(getClass().getCanonicalName()); private final Field serverWorldsField; private final Method getChunkFutureMethod; @@ -348,7 +350,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter (CompoundBinaryTag) toNativeBinary(tag)) + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) ); } @@ -483,9 +485,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) + __ -> (net.minecraft.nbt.CompoundTag) fromNativeLin(nbtData) )); } @@ -609,7 +611,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLin(net.minecraft.nbt.Tag foreign) { if (foreign == null) { return null; } if (foreign instanceof net.minecraft.nbt.CompoundTag) { - Map values = new HashMap<>(); + Map> values = new HashMap<>(); Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); for (String str : foreignKeys) { net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); - values.put(str, toNativeBinary(base)); + values.put(str, toNativeLin(base)); } - return CompoundBinaryTag.from(values); + return LinCompoundTag.of(values); } else if (foreign instanceof net.minecraft.nbt.ByteTag) { - return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); + return LinByteTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { - return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); + return LinByteArrayTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { - return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); + return LinDoubleTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); } else if (foreign instanceof net.minecraft.nbt.FloatTag) { - return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); + return LinFloatTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); } else if (foreign instanceof net.minecraft.nbt.IntTag) { - return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); + return LinIntTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { - return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); + return LinIntArrayTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { - return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); + return LinLongArrayTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); } else if (foreign instanceof net.minecraft.nbt.ListTag) { try { - return toNativeList((net.minecraft.nbt.ListTag) foreign); + return toNativeLinList((net.minecraft.nbt.ListTag) foreign); } catch (Throwable e) { - LOGGER.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); - return ListBinaryTag.empty(); + logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); } } else if (foreign instanceof net.minecraft.nbt.LongTag) { - return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); + return LinLongTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); } else if (foreign instanceof net.minecraft.nbt.ShortTag) { - return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); + return LinShortTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); } else if (foreign instanceof net.minecraft.nbt.StringTag) { - return StringBinaryTag.of(foreign.getAsString()); + return LinStringTag.of(foreign.getAsString()); } else if (foreign instanceof net.minecraft.nbt.EndTag) { - return EndBinaryTag.get(); - } else { - throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); + return LinEndTag.instance(); } + throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); } /** @@ -934,14 +934,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLinList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { + LinListTag.Builder> builder = LinListTag.builder( + LinTagType.fromId(LinTagId.fromId(foreign.getElementType())) + ); for (net.minecraft.nbt.Tag tag : foreign) { - values.add(toNativeBinary(tag)); + builder.add(toNativeLin(tag)); } - return values.build(); + return builder.build(); } /** @@ -951,44 +953,43 @@ public final class PaperweightAdapter implements BukkitImplAdapter foreign) { if (foreign == null) { return null; } - if (foreign instanceof CompoundBinaryTag) { + if (foreign instanceof LinCompoundTag compoundTag) { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - for (String key : ((CompoundBinaryTag) foreign).keySet()) { - tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); + for (var entry : compoundTag.value().entrySet()) { + tag.put(entry.getKey(), fromNativeLin(entry.getValue())); } return tag; - } else if (foreign instanceof ByteBinaryTag) { - return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); - } else if (foreign instanceof ByteArrayBinaryTag) { - return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); - } else if (foreign instanceof DoubleBinaryTag) { - return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); - } else if (foreign instanceof FloatBinaryTag) { - return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); - } else if (foreign instanceof IntBinaryTag) { - return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); - } else if (foreign instanceof IntArrayBinaryTag) { - return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); - } else if (foreign instanceof LongArrayBinaryTag) { - return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); - } else if (foreign instanceof ListBinaryTag) { + } else if (foreign instanceof LinByteTag byteTag) { + return net.minecraft.nbt.ByteTag.valueOf(byteTag.valueAsByte()); + } else if (foreign instanceof LinByteArrayTag byteArrayTag) { + return new net.minecraft.nbt.ByteArrayTag(byteArrayTag.value()); + } else if (foreign instanceof LinDoubleTag doubleTag) { + return net.minecraft.nbt.DoubleTag.valueOf(doubleTag.valueAsDouble()); + } else if (foreign instanceof LinFloatTag floatTag) { + return net.minecraft.nbt.FloatTag.valueOf(floatTag.valueAsFloat()); + } else if (foreign instanceof LinIntTag intTag) { + return net.minecraft.nbt.IntTag.valueOf(intTag.valueAsInt()); + } else if (foreign instanceof LinIntArrayTag intArrayTag) { + return new net.minecraft.nbt.IntArrayTag(intArrayTag.value()); + } else if (foreign instanceof LinLongArrayTag longArrayTag) { + return new net.minecraft.nbt.LongArrayTag(longArrayTag.value()); + } else if (foreign instanceof LinListTag listTag) { net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); - ListBinaryTag foreignList = (ListBinaryTag) foreign; - for (BinaryTag t : foreignList) { - tag.add(fromNativeBinary(t)); + for (var t : listTag.value()) { + tag.add(fromNativeLin(t)); } return tag; - } else if (foreign instanceof LongBinaryTag) { - return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); - } else if (foreign instanceof ShortBinaryTag) { - return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); - } else if (foreign instanceof StringBinaryTag) { - return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); - } else if (foreign instanceof EndBinaryTag) { + } else if (foreign instanceof LinLongTag longTag) { + return net.minecraft.nbt.LongTag.valueOf(longTag.valueAsLong()); + } else if (foreign instanceof LinShortTag shortTag) { + return net.minecraft.nbt.ShortTag.valueOf(shortTag.valueAsShort()); + } else if (foreign instanceof LinStringTag stringTag) { + return net.minecraft.nbt.StringTag.valueOf(stringTag.value()); + } else if (foreign instanceof LinEndTag) { return net.minecraft.nbt.EndTag.INSTANCE; } else { throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); @@ -1027,7 +1028,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter T fixUp(FixType type, T original, int srcVer) { if (type == FixTypes.CHUNK) { - return (T) fixChunk((CompoundBinaryTag) original, srcVer); + return (T) fixChunk((LinCompoundTag) original, srcVer); } else if (type == FixTypes.BLOCK_ENTITY) { - return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); + return (T) fixBlockEntity((LinCompoundTag) original, srcVer); } else if (type == FixTypes.ENTITY) { - return (T) fixEntity((CompoundBinaryTag) original, srcVer); + return (T) fixEntity((LinCompoundTag) original, srcVer); } else if (type == FixTypes.BLOCK_STATE) { return (T) fixBlockState((String) original, srcVer); } else if (type == FixTypes.ITEM_TYPE) { @@ -98,24 +97,23 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return original; } - private CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); + private LinCompoundTag fixChunk(LinCompoundTag originalChunk, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(originalChunk); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); + private LinCompoundTag fixBlockEntity(LinCompoundTag origTileEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origTileEnt); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); + private LinCompoundTag fixEntity(LinCompoundTag origEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origEnt); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - //FAWE end private String fixBlockState(String blockState, int srcVer) { net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState); diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightWorldNativeAccess.java index dc44a165a..c7f3d3f3c 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightWorldNativeAccess.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightWorldNativeAccess.java @@ -19,7 +19,7 @@ package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess; @@ -27,17 +27,20 @@ import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.world.block.BlockState; import net.minecraft.core.BlockPos; +import net.minecraft.nbt.Tag; import net.minecraft.server.level.FullChunkStatus; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.chunk.LevelChunk; import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; import org.bukkit.event.block.BlockPhysicsEvent; +import org.enginehub.linbus.tree.LinCompoundTag; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.util.Objects; -import javax.annotation.Nullable; public class PaperweightWorldNativeAccess implements WorldNativeAccess { private static final int UPDATE = 1; @@ -101,8 +104,15 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess saveTag = () -> { + Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); PaperweightPlatformAdapter.readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work - final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); - final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); - tags.put("Id", StringBinaryTag.of(id)); - return CompoundBinaryTag.from(tags); + final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag); + final Map> tags = NbtUtils.getLinCompoundTagValues(tag); + tags.put("Id", LinStringTag.of(id)); + return LinCompoundTag.of(tags); }; return new LazyBaseEntity(type, saveTag); } else { @@ -514,7 +514,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter iterator = entities.iterator(); while (iterator.hasNext()) { final CompoundTag nativeTag = iterator.next(); - final Map entityTagMap = nativeTag.getValue(); + final Map> entityTagMap = nativeTag.getValue(); final StringTag idTag = (StringTag) entityTagMap.get("Id"); final ListTag posTag = (ListTag) entityTagMap.get("Pos"); final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/nbt/PaperweightLazyCompoundTag.java index dbdece689..f2a694a2f 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/nbt/PaperweightLazyCompoundTag.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/nbt/PaperweightLazyCompoundTag.java @@ -6,8 +6,8 @@ import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import net.minecraft.nbt.NumericTag; +import org.enginehub.linbus.tree.LinCompoundTag; import java.util.ArrayList; import java.util.Collections; @@ -36,7 +36,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { @Override @SuppressWarnings("unchecked") - public Map getValue() { + public Map> getValue() { if (compoundTag == null) { compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); } @@ -44,9 +44,9 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @Override - public CompoundBinaryTag asBinaryTag() { + public LinCompoundTag toLinTag() { getValue(); - return compoundTag.asBinaryTag(); + return compoundTag.toLinTag(); } public boolean containsKey(String key) { @@ -94,10 +94,10 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key) { + public List> getList(String key) { net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); if (tag instanceof net.minecraft.nbt.ListTag nbtList) { - ArrayList list = new ArrayList<>(); + ArrayList> list = new ArrayList<>(); for (net.minecraft.nbt.Tag elem : nbtList) { if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { list.add(new PaperweightLazyCompoundTag(compoundTag)); @@ -120,7 +120,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key, Class listType) { + public > List getList(String key, Class listType) { ListTag listTag = getListTag(key); if (listTag.getType().equals(listType)) { return (List) listTag.getValue(); diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java index f695876cc..e30bb2b2a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java @@ -54,20 +54,6 @@ import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.ByteBinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; -import com.sk89q.worldedit.util.nbt.EndBinaryTag; -import com.sk89q.worldedit.util.nbt.FloatBinaryTag; -import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; -import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.LongBinaryTag; -import com.sk89q.worldedit.util.nbt.ShortBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.biome.BiomeType; @@ -134,9 +120,26 @@ import org.bukkit.craftbukkit.v1_20_R2.util.CraftMagicNumbers; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.generator.ChunkGenerator; +import org.enginehub.linbus.common.LinTagId; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinByteTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinEndTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinLongArrayTag; +import org.enginehub.linbus.tree.LinLongTag; +import org.enginehub.linbus.tree.LinShortTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import org.spigotmc.SpigotConfig; import org.spigotmc.WatchdogThread; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -158,7 +161,6 @@ import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; -import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; @@ -345,7 +347,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter (CompoundBinaryTag) toNativeBinary(tag)) + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) ); } @@ -443,9 +445,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) + __ -> (net.minecraft.nbt.CompoundTag) fromNativeLin(nbtData) )); } @@ -558,7 +560,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLin(net.minecraft.nbt.Tag foreign) { if (foreign == null) { return null; } if (foreign instanceof net.minecraft.nbt.CompoundTag) { - Map values = new HashMap<>(); + Map> values = new HashMap<>(); Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); for (String str : foreignKeys) { net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); - values.put(str, toNativeBinary(base)); + values.put(str, toNativeLin(base)); } - return CompoundBinaryTag.from(values); + return LinCompoundTag.of(values); } else if (foreign instanceof net.minecraft.nbt.ByteTag) { - return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); + return LinByteTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { - return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); + return LinByteArrayTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { - return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); + return LinDoubleTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); } else if (foreign instanceof net.minecraft.nbt.FloatTag) { - return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); + return LinFloatTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); } else if (foreign instanceof net.minecraft.nbt.IntTag) { - return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); + return LinIntTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { - return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); + return LinIntArrayTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { - return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); + return LinLongArrayTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); } else if (foreign instanceof net.minecraft.nbt.ListTag) { try { - return toNativeList((net.minecraft.nbt.ListTag) foreign); + return toNativeLinList((net.minecraft.nbt.ListTag) foreign); } catch (Throwable e) { logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); - return ListBinaryTag.empty(); } } else if (foreign instanceof net.minecraft.nbt.LongTag) { - return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); + return LinLongTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); } else if (foreign instanceof net.minecraft.nbt.ShortTag) { - return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); + return LinShortTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); } else if (foreign instanceof net.minecraft.nbt.StringTag) { - return StringBinaryTag.of(foreign.getAsString()); + return LinStringTag.of(foreign.getAsString()); } else if (foreign instanceof net.minecraft.nbt.EndTag) { - return EndBinaryTag.get(); - } else { - throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); + return LinEndTag.instance(); } + throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); } /** @@ -872,14 +872,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLinList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { + LinListTag.Builder> builder = LinListTag.builder( + LinTagType.fromId(LinTagId.fromId(foreign.getElementType())) + ); for (net.minecraft.nbt.Tag tag : foreign) { - values.add(toNativeBinary(tag)); + builder.add(toNativeLin(tag)); } - return values.build(); + return builder.build(); } /** @@ -889,44 +891,43 @@ public final class PaperweightAdapter implements BukkitImplAdapter foreign) { if (foreign == null) { return null; } - if (foreign instanceof CompoundBinaryTag) { + if (foreign instanceof LinCompoundTag compoundTag) { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - for (String key : ((CompoundBinaryTag) foreign).keySet()) { - tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); + for (var entry : compoundTag.value().entrySet()) { + tag.put(entry.getKey(), fromNativeLin(entry.getValue())); } return tag; - } else if (foreign instanceof ByteBinaryTag) { - return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); - } else if (foreign instanceof ByteArrayBinaryTag) { - return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); - } else if (foreign instanceof DoubleBinaryTag) { - return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); - } else if (foreign instanceof FloatBinaryTag) { - return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); - } else if (foreign instanceof IntBinaryTag) { - return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); - } else if (foreign instanceof IntArrayBinaryTag) { - return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); - } else if (foreign instanceof LongArrayBinaryTag) { - return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); - } else if (foreign instanceof ListBinaryTag) { + } else if (foreign instanceof LinByteTag byteTag) { + return net.minecraft.nbt.ByteTag.valueOf(byteTag.valueAsByte()); + } else if (foreign instanceof LinByteArrayTag byteArrayTag) { + return new net.minecraft.nbt.ByteArrayTag(byteArrayTag.value()); + } else if (foreign instanceof LinDoubleTag doubleTag) { + return net.minecraft.nbt.DoubleTag.valueOf(doubleTag.valueAsDouble()); + } else if (foreign instanceof LinFloatTag floatTag) { + return net.minecraft.nbt.FloatTag.valueOf(floatTag.valueAsFloat()); + } else if (foreign instanceof LinIntTag intTag) { + return net.minecraft.nbt.IntTag.valueOf(intTag.valueAsInt()); + } else if (foreign instanceof LinIntArrayTag intArrayTag) { + return new net.minecraft.nbt.IntArrayTag(intArrayTag.value()); + } else if (foreign instanceof LinLongArrayTag longArrayTag) { + return new net.minecraft.nbt.LongArrayTag(longArrayTag.value()); + } else if (foreign instanceof LinListTag listTag) { net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); - ListBinaryTag foreignList = (ListBinaryTag) foreign; - for (BinaryTag t : foreignList) { - tag.add(fromNativeBinary(t)); + for (var t : listTag.value()) { + tag.add(fromNativeLin(t)); } return tag; - } else if (foreign instanceof LongBinaryTag) { - return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); - } else if (foreign instanceof ShortBinaryTag) { - return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); - } else if (foreign instanceof StringBinaryTag) { - return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); - } else if (foreign instanceof EndBinaryTag) { + } else if (foreign instanceof LinLongTag longTag) { + return net.minecraft.nbt.LongTag.valueOf(longTag.valueAsLong()); + } else if (foreign instanceof LinShortTag shortTag) { + return net.minecraft.nbt.ShortTag.valueOf(shortTag.valueAsShort()); + } else if (foreign instanceof LinStringTag stringTag) { + return net.minecraft.nbt.StringTag.valueOf(stringTag.value()); + } else if (foreign instanceof LinEndTag) { return net.minecraft.nbt.EndTag.INSTANCE; } else { throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightDataConverters.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightDataConverters.java index f7be01738..be25d079a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightDataConverters.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightDataConverters.java @@ -35,7 +35,6 @@ import com.mojang.datafixers.DataFixer; import com.mojang.datafixers.DataFixerBuilder; import com.mojang.datafixers.schemas.Schema; import com.mojang.serialization.Dynamic; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import net.minecraft.core.Direction; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; @@ -48,7 +47,9 @@ import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.item.DyeColor; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinCompoundTag; +import javax.annotation.Nullable; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.EnumMap; @@ -62,7 +63,6 @@ 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) @@ -78,16 +78,15 @@ import javax.annotation.Nullable; @SuppressWarnings({ "rawtypes", "unchecked" }) public class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { - //FAWE start - BinaryTag @SuppressWarnings("unchecked") @Override public T fixUp(FixType type, T original, int srcVer) { if (type == FixTypes.CHUNK) { - return (T) fixChunk((CompoundBinaryTag) original, srcVer); + return (T) fixChunk((LinCompoundTag) original, srcVer); } else if (type == FixTypes.BLOCK_ENTITY) { - return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); + return (T) fixBlockEntity((LinCompoundTag) original, srcVer); } else if (type == FixTypes.ENTITY) { - return (T) fixEntity((CompoundBinaryTag) original, srcVer); + return (T) fixEntity((LinCompoundTag) original, srcVer); } else if (type == FixTypes.BLOCK_STATE) { return (T) fixBlockState((String) original, srcVer); } else if (type == FixTypes.ITEM_TYPE) { @@ -98,24 +97,23 @@ public class PaperweightDataConverters extends DataFixerBuilder implements com.s return original; } - private CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); + private LinCompoundTag fixChunk(LinCompoundTag originalChunk, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(originalChunk); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); + private LinCompoundTag fixBlockEntity(LinCompoundTag origTileEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origTileEnt); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); + private LinCompoundTag fixEntity(LinCompoundTag origEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origEnt); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - //FAWE end private String fixBlockState(String blockState, int srcVer) { net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState); diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightWorldNativeAccess.java index 9e69e4a31..95ecae72a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightWorldNativeAccess.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightWorldNativeAccess.java @@ -24,7 +24,6 @@ import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.block.BlockState; import net.minecraft.core.BlockPos; import net.minecraft.server.level.FullChunkStatus; @@ -34,10 +33,11 @@ import net.minecraft.world.level.chunk.LevelChunk; import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData; import org.bukkit.event.block.BlockPhysicsEvent; +import org.enginehub.linbus.tree.LinCompoundTag; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.util.Objects; -import javax.annotation.Nullable; public class PaperweightWorldNativeAccess implements WorldNativeAccess { private static final int UPDATE = 1; @@ -101,7 +101,7 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess saveTag = () -> { + Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work - final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); - final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); - tags.put("Id", StringBinaryTag.of(id)); - return CompoundBinaryTag.from(tags); + final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag); + final Map> tags = NbtUtils.getLinCompoundTagValues(tag); + tags.put("Id", LinStringTag.of(id)); + return LinCompoundTag.of(tags); }; return new LazyBaseEntity(type, saveTag); } else { @@ -517,7 +517,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter iterator = entities.iterator(); while (iterator.hasNext()) { final CompoundTag nativeTag = iterator.next(); - final Map entityTagMap = nativeTag.getValue(); + final Map> entityTagMap = nativeTag.getValue(); final StringTag idTag = (StringTag) entityTagMap.get("Id"); final ListTag posTag = (ListTag) entityTagMap.get("Pos"); final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/nbt/PaperweightLazyCompoundTag.java index 911da046a..68dbc6b8e 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/nbt/PaperweightLazyCompoundTag.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/nbt/PaperweightLazyCompoundTag.java @@ -6,8 +6,8 @@ import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import net.minecraft.nbt.NumericTag; +import org.enginehub.linbus.tree.LinCompoundTag; import java.util.ArrayList; import java.util.Collections; @@ -36,7 +36,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { @Override @SuppressWarnings("unchecked") - public Map getValue() { + public Map> getValue() { if (compoundTag == null) { compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); } @@ -44,9 +44,9 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @Override - public CompoundBinaryTag asBinaryTag() { + public LinCompoundTag toLinTag() { getValue(); - return compoundTag.asBinaryTag(); + return compoundTag.toLinTag(); } public boolean containsKey(String key) { @@ -94,10 +94,10 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key) { + public List> getList(String key) { net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); if (tag instanceof net.minecraft.nbt.ListTag nbtList) { - ArrayList list = new ArrayList<>(); + ArrayList> list = new ArrayList<>(); for (net.minecraft.nbt.Tag elem : nbtList) { if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { list.add(new PaperweightLazyCompoundTag(compoundTag)); @@ -120,7 +120,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key, Class listType) { + public > List getList(String key, Class listType) { ListTag listTag = getListTag(key); if (listTag.getType().equals(listType)) { return (List) listTag.getValue(); diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java index aa3920ccd..0bc5ba09c 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java @@ -54,20 +54,6 @@ import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.ByteBinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; -import com.sk89q.worldedit.util.nbt.EndBinaryTag; -import com.sk89q.worldedit.util.nbt.FloatBinaryTag; -import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; -import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.LongBinaryTag; -import com.sk89q.worldedit.util.nbt.ShortBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.biome.BiomeType; @@ -134,9 +120,26 @@ import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.generator.ChunkGenerator; +import org.enginehub.linbus.common.LinTagId; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinByteTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinEndTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinLongArrayTag; +import org.enginehub.linbus.tree.LinLongTag; +import org.enginehub.linbus.tree.LinShortTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import org.spigotmc.SpigotConfig; import org.spigotmc.WatchdogThread; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -158,7 +161,6 @@ import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; -import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; @@ -345,7 +347,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter (CompoundBinaryTag) toNativeBinary(tag)) + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) ); } @@ -443,9 +445,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) + __ -> (net.minecraft.nbt.CompoundTag) fromNativeLin(nbtData) )); } @@ -558,7 +560,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLin(net.minecraft.nbt.Tag foreign) { if (foreign == null) { return null; } if (foreign instanceof net.minecraft.nbt.CompoundTag) { - Map values = new HashMap<>(); + Map> values = new HashMap<>(); Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); for (String str : foreignKeys) { net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); - values.put(str, toNativeBinary(base)); + values.put(str, toNativeLin(base)); } - return CompoundBinaryTag.from(values); + return LinCompoundTag.of(values); } else if (foreign instanceof net.minecraft.nbt.ByteTag) { - return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); + return LinByteTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { - return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); + return LinByteArrayTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { - return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); + return LinDoubleTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); } else if (foreign instanceof net.minecraft.nbt.FloatTag) { - return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); + return LinFloatTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); } else if (foreign instanceof net.minecraft.nbt.IntTag) { - return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); + return LinIntTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { - return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); + return LinIntArrayTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { - return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); + return LinLongArrayTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); } else if (foreign instanceof net.minecraft.nbt.ListTag) { try { - return toNativeList((net.minecraft.nbt.ListTag) foreign); + return toNativeLinList((net.minecraft.nbt.ListTag) foreign); } catch (Throwable e) { logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); - return ListBinaryTag.empty(); } } else if (foreign instanceof net.minecraft.nbt.LongTag) { - return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); + return LinLongTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); } else if (foreign instanceof net.minecraft.nbt.ShortTag) { - return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); + return LinShortTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); } else if (foreign instanceof net.minecraft.nbt.StringTag) { - return StringBinaryTag.of(foreign.getAsString()); + return LinStringTag.of(foreign.getAsString()); } else if (foreign instanceof net.minecraft.nbt.EndTag) { - return EndBinaryTag.get(); - } else { - throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); + return LinEndTag.instance(); } + throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); } /** @@ -872,14 +872,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLinList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { + LinListTag.Builder> builder = LinListTag.builder( + LinTagType.fromId(LinTagId.fromId(foreign.getElementType())) + ); for (net.minecraft.nbt.Tag tag : foreign) { - values.add(toNativeBinary(tag)); + builder.add(toNativeLin(tag)); } - return values.build(); + return builder.build(); } /** @@ -889,44 +891,43 @@ public final class PaperweightAdapter implements BukkitImplAdapter foreign) { if (foreign == null) { return null; } - if (foreign instanceof CompoundBinaryTag) { + if (foreign instanceof LinCompoundTag compoundTag) { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - for (String key : ((CompoundBinaryTag) foreign).keySet()) { - tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); + for (var entry : compoundTag.value().entrySet()) { + tag.put(entry.getKey(), fromNativeLin(entry.getValue())); } return tag; - } else if (foreign instanceof ByteBinaryTag) { - return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); - } else if (foreign instanceof ByteArrayBinaryTag) { - return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); - } else if (foreign instanceof DoubleBinaryTag) { - return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); - } else if (foreign instanceof FloatBinaryTag) { - return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); - } else if (foreign instanceof IntBinaryTag) { - return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); - } else if (foreign instanceof IntArrayBinaryTag) { - return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); - } else if (foreign instanceof LongArrayBinaryTag) { - return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); - } else if (foreign instanceof ListBinaryTag) { + } else if (foreign instanceof LinByteTag byteTag) { + return net.minecraft.nbt.ByteTag.valueOf(byteTag.valueAsByte()); + } else if (foreign instanceof LinByteArrayTag byteArrayTag) { + return new net.minecraft.nbt.ByteArrayTag(byteArrayTag.value()); + } else if (foreign instanceof LinDoubleTag doubleTag) { + return net.minecraft.nbt.DoubleTag.valueOf(doubleTag.valueAsDouble()); + } else if (foreign instanceof LinFloatTag floatTag) { + return net.minecraft.nbt.FloatTag.valueOf(floatTag.valueAsFloat()); + } else if (foreign instanceof LinIntTag intTag) { + return net.minecraft.nbt.IntTag.valueOf(intTag.valueAsInt()); + } else if (foreign instanceof LinIntArrayTag intArrayTag) { + return new net.minecraft.nbt.IntArrayTag(intArrayTag.value()); + } else if (foreign instanceof LinLongArrayTag longArrayTag) { + return new net.minecraft.nbt.LongArrayTag(longArrayTag.value()); + } else if (foreign instanceof LinListTag listTag) { net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); - ListBinaryTag foreignList = (ListBinaryTag) foreign; - for (BinaryTag t : foreignList) { - tag.add(fromNativeBinary(t)); + for (var t : listTag.value()) { + tag.add(fromNativeLin(t)); } return tag; - } else if (foreign instanceof LongBinaryTag) { - return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); - } else if (foreign instanceof ShortBinaryTag) { - return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); - } else if (foreign instanceof StringBinaryTag) { - return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); - } else if (foreign instanceof EndBinaryTag) { + } else if (foreign instanceof LinLongTag longTag) { + return net.minecraft.nbt.LongTag.valueOf(longTag.valueAsLong()); + } else if (foreign instanceof LinShortTag shortTag) { + return net.minecraft.nbt.ShortTag.valueOf(shortTag.valueAsShort()); + } else if (foreign instanceof LinStringTag stringTag) { + return net.minecraft.nbt.StringTag.valueOf(stringTag.value()); + } else if (foreign instanceof LinEndTag) { return net.minecraft.nbt.EndTag.INSTANCE; } else { throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightDataConverters.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightDataConverters.java index 175174b75..3a80b6a3a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightDataConverters.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightDataConverters.java @@ -35,8 +35,6 @@ import com.mojang.datafixers.DataFixer; import com.mojang.datafixers.DataFixerBuilder; import com.mojang.datafixers.schemas.Schema; import com.mojang.serialization.Dynamic; -import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3.PaperweightAdapter; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import net.minecraft.core.Direction; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; @@ -49,7 +47,9 @@ import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.item.DyeColor; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinCompoundTag; +import javax.annotation.Nullable; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.EnumMap; @@ -63,7 +63,6 @@ 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) @@ -79,16 +78,15 @@ import javax.annotation.Nullable; @SuppressWarnings({ "rawtypes", "unchecked" }) public class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { - //FAWE start - BinaryTag @SuppressWarnings("unchecked") @Override public T fixUp(FixType type, T original, int srcVer) { if (type == FixTypes.CHUNK) { - return (T) fixChunk((CompoundBinaryTag) original, srcVer); + return (T) fixChunk((LinCompoundTag) original, srcVer); } else if (type == FixTypes.BLOCK_ENTITY) { - return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); + return (T) fixBlockEntity((LinCompoundTag) original, srcVer); } else if (type == FixTypes.ENTITY) { - return (T) fixEntity((CompoundBinaryTag) original, srcVer); + return (T) fixEntity((LinCompoundTag) original, srcVer); } else if (type == FixTypes.BLOCK_STATE) { return (T) fixBlockState((String) original, srcVer); } else if (type == FixTypes.ITEM_TYPE) { @@ -99,24 +97,23 @@ public class PaperweightDataConverters extends DataFixerBuilder implements com.s return original; } - private CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); + private LinCompoundTag fixChunk(LinCompoundTag originalChunk, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(originalChunk); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); + private LinCompoundTag fixBlockEntity(LinCompoundTag origTileEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origTileEnt); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); + private LinCompoundTag fixEntity(LinCompoundTag origEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origEnt); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - //FAWE end private String fixBlockState(String blockState, int srcVer) { net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState); diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightWorldNativeAccess.java index b50ead936..7e5a171f6 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightWorldNativeAccess.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightWorldNativeAccess.java @@ -19,25 +19,28 @@ package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.block.BlockState; import net.minecraft.core.BlockPos; +import net.minecraft.nbt.Tag; import net.minecraft.server.level.FullChunkStatus; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.chunk.LevelChunk; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; import org.bukkit.event.block.BlockPhysicsEvent; +import org.enginehub.linbus.tree.LinCompoundTag; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.util.Objects; -import javax.annotation.Nullable; public class PaperweightWorldNativeAccess implements WorldNativeAccess { private static final int UPDATE = 1; @@ -101,8 +104,15 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess saveTag = () -> { + Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work - final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); - final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); - tags.put("Id", StringBinaryTag.of(id)); - return CompoundBinaryTag.from(tags); + final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag); + final Map> tags = NbtUtils.getLinCompoundTagValues(tag); + tags.put("Id", LinStringTag.of(id)); + return LinCompoundTag.of(tags); }; return new LazyBaseEntity(type, saveTag); } else { @@ -517,7 +517,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter iterator = entities.iterator(); while (iterator.hasNext()) { final CompoundTag nativeTag = iterator.next(); - final Map entityTagMap = nativeTag.getValue(); + final Map> entityTagMap = nativeTag.getValue(); final StringTag idTag = (StringTag) entityTagMap.get("Id"); final ListTag posTag = (ListTag) entityTagMap.get("Pos"); final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/nbt/PaperweightLazyCompoundTag.java index 9a8a51896..1d27f17a7 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/nbt/PaperweightLazyCompoundTag.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/nbt/PaperweightLazyCompoundTag.java @@ -6,8 +6,8 @@ import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import net.minecraft.nbt.NumericTag; +import org.enginehub.linbus.tree.LinCompoundTag; import java.util.ArrayList; import java.util.Collections; @@ -36,7 +36,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { @Override @SuppressWarnings("unchecked") - public Map getValue() { + public Map> getValue() { if (compoundTag == null) { compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); } @@ -44,9 +44,9 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @Override - public CompoundBinaryTag asBinaryTag() { + public LinCompoundTag toLinTag() { getValue(); - return compoundTag.asBinaryTag(); + return compoundTag.toLinTag(); } public boolean containsKey(String key) { @@ -94,10 +94,10 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key) { + public List> getList(String key) { net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); if (tag instanceof net.minecraft.nbt.ListTag nbtList) { - ArrayList list = new ArrayList<>(); + ArrayList> list = new ArrayList<>(); for (net.minecraft.nbt.Tag elem : nbtList) { if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { list.add(new PaperweightLazyCompoundTag(compoundTag)); @@ -120,7 +120,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key, Class listType) { + public > List getList(String key, Class listType) { ListTag listTag = getListTag(key); if (listTag.getType().equals(listType)) { return (List) listTag.getValue(); diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java index 964be1398..503330ad5 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java @@ -54,20 +54,6 @@ import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.ByteBinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; -import com.sk89q.worldedit.util.nbt.EndBinaryTag; -import com.sk89q.worldedit.util.nbt.FloatBinaryTag; -import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; -import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.LongBinaryTag; -import com.sk89q.worldedit.util.nbt.ShortBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.biome.BiomeType; @@ -139,9 +125,26 @@ import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.generator.ChunkGenerator; +import org.enginehub.linbus.common.LinTagId; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinByteTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinEndTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinLongArrayTag; +import org.enginehub.linbus.tree.LinLongTag; +import org.enginehub.linbus.tree.LinShortTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import org.spigotmc.SpigotConfig; import org.spigotmc.WatchdogThread; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -163,7 +166,6 @@ import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; -import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; @@ -375,7 +377,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter (CompoundBinaryTag) toNativeBinary(tag)) + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) ); } @@ -473,9 +475,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) + (blockEntity, registryAccess) -> (net.minecraft.nbt.CompoundTag) fromNativeLin(nbtData) )); } @@ -619,7 +621,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter (CompoundBinaryTag) toNativeBinary(tag)), + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)), itemStack.getAmount() ); } @@ -811,7 +813,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLin(net.minecraft.nbt.Tag foreign) { if (foreign == null) { return null; } if (foreign instanceof net.minecraft.nbt.CompoundTag) { - Map values = new HashMap<>(); + Map> values = new HashMap<>(); Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); for (String str : foreignKeys) { net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); - values.put(str, toNativeBinary(base)); + values.put(str, toNativeLin(base)); } - return CompoundBinaryTag.from(values); + return LinCompoundTag.of(values); } else if (foreign instanceof net.minecraft.nbt.ByteTag) { - return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); + return LinByteTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { - return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); + return LinByteArrayTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { - return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); + return LinDoubleTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); } else if (foreign instanceof net.minecraft.nbt.FloatTag) { - return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); + return LinFloatTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); } else if (foreign instanceof net.minecraft.nbt.IntTag) { - return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); + return LinIntTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { - return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); + return LinIntArrayTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { - return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); + return LinLongArrayTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); } else if (foreign instanceof net.minecraft.nbt.ListTag) { try { - return toNativeList((net.minecraft.nbt.ListTag) foreign); + return toNativeLinList((net.minecraft.nbt.ListTag) foreign); } catch (Throwable e) { logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); - return ListBinaryTag.empty(); } } else if (foreign instanceof net.minecraft.nbt.LongTag) { - return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); + return LinLongTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); } else if (foreign instanceof net.minecraft.nbt.ShortTag) { - return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); + return LinShortTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); } else if (foreign instanceof net.minecraft.nbt.StringTag) { - return StringBinaryTag.of(foreign.getAsString()); + return LinStringTag.of(foreign.getAsString()); } else if (foreign instanceof net.minecraft.nbt.EndTag) { - return EndBinaryTag.get(); - } else { - throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); + return LinEndTag.instance(); } + throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); } /** @@ -946,17 +946,19 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLinList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { + LinListTag.Builder> builder = LinListTag.builder( + LinTagType.fromId(LinTagId.fromId(foreign.getElementType())) + ); for (net.minecraft.nbt.Tag tag : foreign) { - values.add(toNativeBinary(tag)); + builder.add(toNativeLin(tag)); } - return values.build(); + return builder.build(); } /** @@ -966,44 +968,43 @@ public final class PaperweightAdapter implements BukkitImplAdapter foreign) { if (foreign == null) { return null; } - if (foreign instanceof CompoundBinaryTag) { + if (foreign instanceof LinCompoundTag compoundTag) { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - for (String key : ((CompoundBinaryTag) foreign).keySet()) { - tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); + for (var entry : compoundTag.value().entrySet()) { + tag.put(entry.getKey(), fromNativeLin(entry.getValue())); } return tag; - } else if (foreign instanceof ByteBinaryTag) { - return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); - } else if (foreign instanceof ByteArrayBinaryTag) { - return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); - } else if (foreign instanceof DoubleBinaryTag) { - return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); - } else if (foreign instanceof FloatBinaryTag) { - return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); - } else if (foreign instanceof IntBinaryTag) { - return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); - } else if (foreign instanceof IntArrayBinaryTag) { - return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); - } else if (foreign instanceof LongArrayBinaryTag) { - return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); - } else if (foreign instanceof ListBinaryTag) { + } else if (foreign instanceof LinByteTag byteTag) { + return net.minecraft.nbt.ByteTag.valueOf(byteTag.valueAsByte()); + } else if (foreign instanceof LinByteArrayTag byteArrayTag) { + return new net.minecraft.nbt.ByteArrayTag(byteArrayTag.value()); + } else if (foreign instanceof LinDoubleTag doubleTag) { + return net.minecraft.nbt.DoubleTag.valueOf(doubleTag.valueAsDouble()); + } else if (foreign instanceof LinFloatTag floatTag) { + return net.minecraft.nbt.FloatTag.valueOf(floatTag.valueAsFloat()); + } else if (foreign instanceof LinIntTag intTag) { + return net.minecraft.nbt.IntTag.valueOf(intTag.valueAsInt()); + } else if (foreign instanceof LinIntArrayTag intArrayTag) { + return new net.minecraft.nbt.IntArrayTag(intArrayTag.value()); + } else if (foreign instanceof LinLongArrayTag longArrayTag) { + return new net.minecraft.nbt.LongArrayTag(longArrayTag.value()); + } else if (foreign instanceof LinListTag listTag) { net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); - ListBinaryTag foreignList = (ListBinaryTag) foreign; - for (BinaryTag t : foreignList) { - tag.add(fromNativeBinary(t)); + for (var t : listTag.value()) { + tag.add(fromNativeLin(t)); } return tag; - } else if (foreign instanceof LongBinaryTag) { - return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); - } else if (foreign instanceof ShortBinaryTag) { - return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); - } else if (foreign instanceof StringBinaryTag) { - return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); - } else if (foreign instanceof EndBinaryTag) { + } else if (foreign instanceof LinLongTag longTag) { + return net.minecraft.nbt.LongTag.valueOf(longTag.valueAsLong()); + } else if (foreign instanceof LinShortTag shortTag) { + return net.minecraft.nbt.ShortTag.valueOf(shortTag.valueAsShort()); + } else if (foreign instanceof LinStringTag stringTag) { + return net.minecraft.nbt.StringTag.valueOf(stringTag.value()); + } else if (foreign instanceof LinEndTag) { return net.minecraft.nbt.EndTag.INSTANCE; } else { throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightDataConverters.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightDataConverters.java index 39807b86d..c566f0ae8 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightDataConverters.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightDataConverters.java @@ -35,8 +35,6 @@ import com.mojang.datafixers.DataFixer; import com.mojang.datafixers.DataFixerBuilder; import com.mojang.datafixers.schemas.Schema; import com.mojang.serialization.Dynamic; -import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R4.PaperweightAdapter; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import net.minecraft.core.Direction; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.StringTag; @@ -51,7 +49,9 @@ import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.item.DyeColor; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinCompoundTag; +import javax.annotation.Nullable; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.EnumMap; @@ -65,7 +65,6 @@ 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) @@ -81,16 +80,15 @@ import javax.annotation.Nullable; @SuppressWarnings({ "rawtypes", "unchecked" }) public class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { - //FAWE start - BinaryTag @SuppressWarnings("unchecked") @Override public T fixUp(FixType type, T original, int srcVer) { if (type == FixTypes.CHUNK) { - return (T) fixChunk((CompoundBinaryTag) original, srcVer); + return (T) fixChunk((LinCompoundTag) original, srcVer); } else if (type == FixTypes.BLOCK_ENTITY) { - return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); + return (T) fixBlockEntity((LinCompoundTag) original, srcVer); } else if (type == FixTypes.ENTITY) { - return (T) fixEntity((CompoundBinaryTag) original, srcVer); + return (T) fixEntity((LinCompoundTag) original, srcVer); } else if (type == FixTypes.BLOCK_STATE) { return (T) fixBlockState((String) original, srcVer); } else if (type == FixTypes.ITEM_TYPE) { @@ -101,24 +99,23 @@ public class PaperweightDataConverters extends DataFixerBuilder implements com.s return original; } - private CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); + private LinCompoundTag fixChunk(LinCompoundTag originalChunk, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(originalChunk); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); + private LinCompoundTag fixBlockEntity(LinCompoundTag origTileEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origTileEnt); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); + private LinCompoundTag fixEntity(LinCompoundTag origEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origEnt); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - //FAWE end private String fixBlockState(String blockState, int srcVer) { net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState); diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightWorldNativeAccess.java index f7e5cee3f..4b82a2eb0 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightWorldNativeAccess.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightWorldNativeAccess.java @@ -24,7 +24,6 @@ import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.block.BlockState; import net.minecraft.core.BlockPos; import net.minecraft.server.level.FullChunkStatus; @@ -34,10 +33,11 @@ import net.minecraft.world.level.chunk.LevelChunk; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.event.block.BlockPhysicsEvent; +import org.enginehub.linbus.tree.LinCompoundTag; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.util.Objects; -import javax.annotation.Nullable; public class PaperweightWorldNativeAccess implements WorldNativeAccess { private static final int UPDATE = 1; @@ -101,7 +101,7 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess saveTag = () -> { + Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work - final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); - final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); - tags.put("Id", StringBinaryTag.of(id)); - return CompoundBinaryTag.from(tags); + final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag); + final Map> tags = NbtUtils.getLinCompoundTagValues(tag); + tags.put("Id", LinStringTag.of(id)); + return LinCompoundTag.of(tags); }; return new LazyBaseEntity(type, saveTag); } else { @@ -538,7 +538,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter (CompoundBinaryTag) toNativeBinary(tag)), + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)), itemStack.getAmount() ); } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweWorldNativeAccess.java index d66057313..8d33efb0f 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweWorldNativeAccess.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweWorldNativeAccess.java @@ -9,15 +9,14 @@ import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.block.BlockState; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.FullChunkStatus; +import net.minecraft.server.level.ServerChunkCache; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; @@ -25,6 +24,7 @@ import net.minecraft.world.level.chunk.LevelChunk; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.event.block.BlockPhysicsEvent; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; import java.lang.ref.WeakReference; @@ -133,14 +133,14 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess iterator = entities.iterator(); while (iterator.hasNext()) { final CompoundTag nativeTag = iterator.next(); - final Map entityTagMap = nativeTag.getValue(); + final Map> entityTagMap = nativeTag.getValue(); final StringTag idTag = (StringTag) entityTagMap.get("Id"); final ListTag posTag = (ListTag) entityTagMap.get("Pos"); final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/nbt/PaperweightLazyCompoundTag.java index 11d3c940a..52111a4fd 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/nbt/PaperweightLazyCompoundTag.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/nbt/PaperweightLazyCompoundTag.java @@ -6,8 +6,8 @@ import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import net.minecraft.nbt.NumericTag; +import org.enginehub.linbus.tree.LinCompoundTag; import java.util.ArrayList; import java.util.Collections; @@ -36,7 +36,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { @Override @SuppressWarnings("unchecked") - public Map getValue() { + public Map> getValue() { if (compoundTag == null) { compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); } @@ -44,9 +44,9 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @Override - public CompoundBinaryTag asBinaryTag() { + public LinCompoundTag toLinTag() { getValue(); - return compoundTag.asBinaryTag(); + return compoundTag.toLinTag(); } public boolean containsKey(String key) { @@ -94,10 +94,10 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key) { + public List> getList(String key) { net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); if (tag instanceof net.minecraft.nbt.ListTag nbtList) { - ArrayList list = new ArrayList<>(); + ArrayList> list = new ArrayList<>(); for (net.minecraft.nbt.Tag elem : nbtList) { if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { list.add(new PaperweightLazyCompoundTag(compoundTag)); @@ -120,7 +120,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key, Class listType) { + public > List getList(String key, Class listType) { ListTag listTag = getListTag(key); if (listTag.getType().equals(listType)) { return (List) listTag.getValue(); diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index ce6c9d1b1..258d9b83e 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -178,9 +178,6 @@ tasks.named("shadowJar") { relocate("org.lz4", "com.fastasyncworldedit.core.lz4") { include(dependency("org.lz4:lz4-java:1.8.0")) } - relocate("net.kyori", "com.fastasyncworldedit.core.adventure") { - include(dependency("net.kyori:adventure-nbt:4.17.0")) - } relocate("com.zaxxer", "com.fastasyncworldedit.core.math") { include(dependency("com.zaxxer:SparseBitSet:1.3")) } diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IDelegateBukkitImplAdapter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IDelegateBukkitImplAdapter.java index e0d13a36b..5cbc0f6b8 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IDelegateBukkitImplAdapter.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IDelegateBukkitImplAdapter.java @@ -12,11 +12,8 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.DataFixer; 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.block.BlockType; @@ -33,6 +30,8 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinTag; import javax.annotation.Nullable; import java.util.Map; @@ -81,7 +80,7 @@ public interface IDelegateBukkitImplAdapter extends BukkitImplAdapter { } @Override - default void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { + default void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) { getParent().sendFakeNBT(player, pos, nbtData); } @@ -131,8 +130,8 @@ public interface IDelegateBukkitImplAdapter extends BukkitImplAdapter { } @Override - default BinaryTag toNativeBinary(T foreign) { - return getParent().toNativeBinary(foreign); + default LinTag toNativeLin(T foreign) { + return getParent().toNativeLin(foreign); } @Override @@ -141,8 +140,8 @@ public interface IDelegateBukkitImplAdapter extends BukkitImplAdapter { } @Override - default T fromNativeBinary(BinaryTag foreign) { - return getParent().fromNativeBinary(foreign); + default T fromNativeLin(LinTag foreign) { + return getParent().fromNativeLin(foreign); } @Override diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java index 792f3937e..4b798981e 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java @@ -194,7 +194,7 @@ public class FaweDelegateSchematicHandler { } else { try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream(new ParallelGZIPOutputStream(stream))) { - Map map = tag.getValue(); + Map> map = tag.getValue(); output.writeNamedTag("Schematic", map.getOrDefault("Schematic", tag)); } } @@ -226,7 +226,7 @@ public class FaweDelegateSchematicHandler { try { try (ParallelGZIPOutputStream gzip = new ParallelGZIPOutputStream(output)) { try (NBTOutputStream nos = new NBTOutputStream(gzip)) { - Map map = weTag.getValue(); + Map> map = weTag.getValue(); nos.writeNamedTag("Schematic", map.getOrDefault("Schematic", weTag)); } } 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 44918557e..4ced1a680 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 @@ -45,7 +45,6 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -61,6 +60,7 @@ import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.permissions.PermissionAttachment; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -430,7 +430,7 @@ public class BukkitPlayer extends AbstractPlayerActor { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); if (adapter != null) { if (block.getBlockType() == BlockTypes.STRUCTURE_BLOCK && block instanceof BaseBlock) { - CompoundBinaryTag nbt = ((BaseBlock) block).getNbt(); + LinCompoundTag nbt = ((BaseBlock) block).getNbt(); if (nbt != null) { adapter.sendFakeNBT(player, pos, nbt); adapter.sendFakeOP(player); diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java index a34494ce5..d656e874a 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java @@ -27,7 +27,7 @@ import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; -import com.sk89q.jnbt.AdventureNBTConverter; +import com.sk89q.jnbt.LinBusConverter; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; @@ -41,8 +41,6 @@ import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.biome.BiomeType; @@ -61,6 +59,8 @@ import org.bukkit.block.data.BlockData; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinTag; import javax.annotation.Nullable; import java.util.Arrays; @@ -183,7 +183,7 @@ public interface BukkitImplAdapter extends IBukkitAdapter { * @param pos The position * @param nbtData The NBT Data */ - void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData); + void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData); /** * Make the client think it has operator status. @@ -291,11 +291,11 @@ public interface BukkitImplAdapter extends IBukkitAdapter { @Deprecated default Tag toNative(T foreign) { - return AdventureNBTConverter.fromAdventure(toNativeBinary(foreign)); + return LinBusConverter.toJnbtTag(toNativeLin(foreign)); } - default BinaryTag toNativeBinary(T foreign) { - return toNative(foreign).asBinaryTag(); + default LinTag toNativeLin(T foreign) { + return toNative(foreign).toLinTag(); } @Deprecated @@ -303,14 +303,14 @@ public interface BukkitImplAdapter extends IBukkitAdapter { if (foreign == null) { return null; } - return fromNativeBinary(foreign.asBinaryTag()); + return fromNativeLin(foreign.toLinTag()); } - default T fromNativeBinary(BinaryTag foreign) { + default T fromNativeLin(LinTag foreign) { if (foreign == null) { return null; } - return fromNative(AdventureNBTConverter.fromAdventure(foreign)); + return fromNative(LinBusConverter.toJnbtTag(foreign)); } @Nullable diff --git a/worldedit-core/build.gradle.kts b/worldedit-core/build.gradle.kts index d9794d9f6..d5839d99f 100644 --- a/worldedit-core/build.gradle.kts +++ b/worldedit-core/build.gradle.kts @@ -46,7 +46,6 @@ dependencies { implementation(libs.findbugs) implementation(libs.rhino) compileOnly(libs.adventureApi) - compileOnlyApi(libs.adventureNbt) compileOnlyApi(libs.adventureMiniMessage) implementation(libs.zstd) { isTransitive = false } compileOnly(libs.paster) @@ -56,10 +55,10 @@ dependencies { antlr(libs.antlr4) implementation(libs.antlr4Runtime) implementation(libs.jsonSimple) { isTransitive = false } + implementation(platform(libs.linBus.bom)) // Tests testRuntimeOnly(libs.log4jCore) - testImplementation(libs.adventureNbt) testImplementation(libs.parallelgzip) } 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 0420d0994..1f0efe7a1 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 @@ -125,7 +125,7 @@ public class MobSpawnerBlock extends BaseBlock { @Override public CompoundTag getNbtData() { - Map values = new HashMap<>(); + Map> values = new HashMap<>(); values.put("Delay", new ShortTag(delay)); values.put("SpawnCount", new ShortTag(spawnCount)); values.put("SpawnRange", new ShortTag(spawnRange)); @@ -170,7 +170,7 @@ public class MobSpawnerBlock extends BaseBlock { return; } - Map values = rootTag.getValue(); + Map> values = rootTag.getValue(); Tag t = values.get("id"); if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals(getNbtId())) { diff --git a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java index 333c3336b..bf9adfa38 100644 --- a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java +++ b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java @@ -104,7 +104,7 @@ public class SignBlock extends BaseBlock { @Override public CompoundTag getNbtData() { - Map values = new HashMap<>(); + Map> values = new HashMap<>(); if (isLegacy()) { values.put("Text1", new StringTag(text[0])); values.put("Text2", new StringTag(text[1])); @@ -112,7 +112,7 @@ public class SignBlock extends BaseBlock { values.put("Text4", new StringTag(text[3])); } else { ListTag messages = new ListTag(StringTag.class, Arrays.stream(text).map(StringTag::new).collect(Collectors.toList())); - Map frontTextTag = new HashMap<>(); + Map> frontTextTag = new HashMap<>(); frontTextTag.put("messages", messages); values.put("front_text", new CompoundTag(frontTextTag)); } @@ -125,9 +125,9 @@ public class SignBlock extends BaseBlock { return; } - Map values = rootTag.getValue(); + Map> values = rootTag.getValue(); - Tag t; + Tag t; text = new String[]{EMPTY, EMPTY, EMPTY, EMPTY}; diff --git a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java index a60ffbc09..a5b405f47 100644 --- a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java +++ b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java @@ -100,8 +100,8 @@ public class SkullBlock extends BaseBlock { @Override public CompoundTag getNbtData() { - Map values = new HashMap<>(); - Map inner = new HashMap<>(); + Map> values = new HashMap<>(); + Map> inner = new HashMap<>(); inner.put("Name", new StringTag(owner)); values.put(DeprecationUtil.getHeadOwnerKey(), new CompoundTag(inner)); return new CompoundTag(values); @@ -113,7 +113,7 @@ public class SkullBlock extends BaseBlock { return; } - Map values = rootTag.getValue(); + Map> values = rootTag.getValue(); Tag t; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java index 46a3a1574..526570296 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java @@ -532,7 +532,7 @@ public enum FaweCache implements Trimable { } public CompoundTag asTag(Map value) { - HashMap map = new HashMap<>(); + HashMap> map = new HashMap<>(); for (Map.Entry entry : value.entrySet()) { Object child = entry.getValue(); Tag tag = asTag(child); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/entity/LazyBaseEntity.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/entity/LazyBaseEntity.java index f591cf826..325cd4191 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/entity/LazyBaseEntity.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/entity/LazyBaseEntity.java @@ -3,25 +3,25 @@ package com.fastasyncworldedit.core.entity; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.util.TaskManager; import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.entity.EntityType; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; import java.util.function.Supplier; public class LazyBaseEntity extends BaseEntity { - private Supplier saveTag; + private Supplier saveTag; - public LazyBaseEntity(EntityType type, Supplier saveTag) { + public LazyBaseEntity(EntityType type, Supplier saveTag) { super(type); this.saveTag = saveTag; } @Nullable @Override - public CompoundBinaryTag getNbt() { - Supplier tmp = saveTag; + public LinCompoundTag getNbt() { + Supplier tmp = saveTag; if (tmp != null) { saveTag = null; if (Fawe.isMainThread()) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java index ded96d5aa..c0b49c333 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java @@ -29,8 +29,6 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; @@ -81,7 +79,7 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc return block; } CompoundTag nbt = localBlock.getNbtData(); - Map value = new HashMap<>(nbt.getValue()); + Map> value = new HashMap<>(nbt.getValue()); for (String key : strip) { value.remove(key); } @@ -93,7 +91,7 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc return entity; } CompoundTag nbt = entity.getNbtData(); - Map value = new HashMap<>(nbt.getValue()); + Map> value = new HashMap<>(nbt.getValue()); for (String key : strip) { value.remove(key); } @@ -110,7 +108,7 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc } boolean isBv3ChunkMap = tiles instanceof BlockVector3ChunkMap; for (final Map.Entry entry : tiles.entrySet()) { - ImmutableMap.Builder map = ImmutableMap.builder(); + ImmutableMap.Builder> map = ImmutableMap.builder(); final AtomicBoolean isStripped = new AtomicBoolean(false); entry.getValue().getValue().forEach((k, v) -> { if (strip.contains(k.toLowerCase())) { @@ -132,7 +130,7 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc Iterator iterator = entities.iterator(); while (iterator.hasNext()) { CompoundTag entity = iterator.next(); - ImmutableMap.Builder map = ImmutableMap.builder(); + ImmutableMap.Builder> map = ImmutableMap.builder(); final AtomicBoolean isStripped = new AtomicBoolean(false); entity.getValue().forEach((k, v) -> { if (strip.contains(k.toUpperCase(Locale.ROOT))) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java index 6a306fc44..77447ac4c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java @@ -152,7 +152,7 @@ public class CPUOptimizedClipboard extends LinearClipboard { public Collection getTileEntities() { convertTilesToIndex(); nbtMapIndex.replaceAll((index, tag) -> { - Map values = new HashMap<>(tag.getValue()); + Map> values = new HashMap<>(tag.getValue()); if (!values.containsKey("x")) { int y = index / getArea(); index -= y * getArea(); @@ -176,7 +176,7 @@ public class CPUOptimizedClipboard extends LinearClipboard { } private boolean setTile(int index, CompoundTag tag) { - final Map values = new HashMap<>(tag.getValue()); + final Map> values = new HashMap<>(tag.getValue()); values.remove("x"); values.remove("y"); values.remove("z"); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java index f42cdbbff..dc7193394 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java @@ -586,7 +586,7 @@ public class DiskOptimizedClipboard extends LinearClipboard { for (BlockArrayClipboard.ClipboardEntity entity : entities) { if (entity.getState() != null && entity.getState().getNbtData() != null) { CompoundTag data = entity.getState().getNbtData(); - HashMap value = new HashMap<>(data.getValue()); + HashMap> value = new HashMap<>(data.getValue()); List pos = new ArrayList<>(3); pos.add(new DoubleTag(entity.getLocation().x())); pos.add(new DoubleTag(entity.getLocation().x())); @@ -710,7 +710,7 @@ public class DiskOptimizedClipboard extends LinearClipboard { @Override public boolean setTile(int x, int y, int z, CompoundTag tag) { - final Map values = new HashMap<>(tag.getValue()); + final Map> values = new HashMap<>(tag.getValue()); values.put("x", new IntTag(x)); values.put("y", new IntTag(y)); values.put("z", new IntTag(z)); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java index 143168504..2e65f59ca 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java @@ -106,7 +106,7 @@ public abstract class LinearClipboard extends SimpleClipboard { @Nullable @Override public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { - Map map = new HashMap<>(entity.getNbtData().getValue()); + Map> map = new HashMap<>(entity.getNbtData().getValue()); NBTUtils.addUUIDToMap(map, uuid); entity.setNbtData(new CompoundTag(map)); BlockArrayClipboard.ClipboardEntity ret = new BlockArrayClipboard.ClipboardEntity(location, entity); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java index 6c7a910f2..426cbc32a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java @@ -254,7 +254,7 @@ public class MemoryOptimizedClipboard extends LinearClipboard { @Override public boolean setTile(int x, int y, int z, CompoundTag tag) { - final Map values = new HashMap<>(tag.getValue()); + final Map> values = new HashMap<>(tag.getValue()); values.put("x", new IntTag(x)); values.put("y", new IntTag(y)); values.put("z", new IntTag(z)); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java index 156e38544..b32d42c04 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java @@ -9,7 +9,7 @@ import com.fastasyncworldedit.core.internal.io.FaweInputStream; import com.fastasyncworldedit.core.internal.io.FaweOutputStream; import com.fastasyncworldedit.core.jnbt.streamer.StreamDelegate; import com.fastasyncworldedit.core.jnbt.streamer.ValueReader; -import com.sk89q.jnbt.AdventureNBTConverter; +import com.sk89q.jnbt.LinBusConverter; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.NBTInputStream; @@ -109,10 +109,10 @@ public class FastSchematicReader extends NBTSchematicReader { if (fixer == null || dataVersion == -1) { return tag; } - //FAWE start - BinaryTag - return (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp( + //FAWE start - LinTag + return (CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp( DataFixer.FixTypes.BLOCK_ENTITY, - tag.asBinaryTag(), + tag.toLinTag(), dataVersion )); //FAWE end @@ -122,10 +122,10 @@ public class FastSchematicReader extends NBTSchematicReader { if (fixer == null || dataVersion == -1) { return tag; } - //FAWE start - BinaryTag - return (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp( + //FAWE start - LinTag + return (CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp( DataFixer.FixTypes.ENTITY, - tag.asBinaryTag(), + tag.toLinTag(), dataVersion )); //FAWE end @@ -344,7 +344,7 @@ public class FastSchematicReader extends NBTSchematicReader { y = pos[1]; z = pos[2]; } - Map values = new HashMap<>(tile.getValue()); + Map> values = new HashMap<>(tile.getValue()); Tag id = values.get("Id"); if (id != null) { values.put("x", new IntTag(x)); @@ -371,7 +371,7 @@ public class FastSchematicReader extends NBTSchematicReader { // entities if (entities != null && !entities.isEmpty()) { for (Map entRaw : entities) { - Map value = new HashMap<>(FaweCache.INSTANCE.asTag(entRaw).getValue()); + Map> value = new HashMap<>(FaweCache.INSTANCE.asTag(entRaw).getValue()); StringTag id = (StringTag) value.get("Id"); if (id == null) { id = (StringTag) value.get("id"); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java index 65a4a0e86..ac86fb249 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java @@ -149,7 +149,7 @@ public class FastSchematicWriter implements ClipboardWriter { BaseBlock block = pos.getFullBlock(finalClipboard); CompoundTag nbt = block.getNbtData(); if (nbt != null) { - Map values = new HashMap<>(nbt.getValue()); + Map> values = new HashMap<>(nbt.getValue()); // Positions are kept in NBT, we don't want that. values.remove("x"); @@ -223,7 +223,7 @@ public class FastSchematicWriter implements ClipboardWriter { BaseEntity state = entity.getState(); if (state != null) { - Map values = new HashMap<>(); + Map> values = new HashMap<>(); // Put NBT provided data CompoundTag rawTag = state.getNbtData(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java index 91fb75495..0915766cc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java @@ -70,7 +70,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { throw new IOException("Root tag has name - are you sure this is a structure?"); } - Map tags = ((CompoundTag) rootTag.getTag()).getValue(); + Map> tags = ((CompoundTag) rootTag.getTag()).getValue(); ListTag size = (ListTag) tags.get("size"); int width = size.getInt(0); @@ -89,13 +89,13 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { BlockState[] combinedArray = new BlockState[palette.size()]; for (int i = 0; i < palette.size(); i++) { CompoundTag compound = palette.get(i); - Map map = compound.getValue(); + Map> map = compound.getValue(); String name = ((StringTag) map.get("Name")).getValue(); BlockType type = BlockTypes.get(name); BlockState state = type.getDefaultState(); CompoundTag properties = (CompoundTag) map.get("Properties"); if (properties != null) { - for (Map.Entry entry : properties.getValue().entrySet()) { + for (Map.Entry> entry : properties.getValue().entrySet()) { String key = entry.getKey(); String value = ((StringTag) entry.getValue()).getValue(); Property property = type.getProperty(key); @@ -108,7 +108,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { List blocksList = (List) tags.get("blocks").getValue(); try { for (CompoundTag compound : blocksList) { - Map blockMap = compound.getValue(); + Map> blockMap = compound.getValue(); IntTag stateTag = (IntTag) blockMap.get("state"); ListTag posTag = (ListTag) blockMap.get("pos"); BlockState state = combinedArray[stateTag.getValue()]; @@ -136,7 +136,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { if (entities != null) { List entityList = (List) (List) entities.getValue(); for (CompoundTag entityEntry : entityList) { - Map entityEntryMap = entityEntry.getValue(); + Map> entityEntryMap = entityEntry.getValue(); ListTag posTag = (ListTag) entityEntryMap.get("pos"); CompoundTag nbtTag = (CompoundTag) entityEntryMap.get("nbt"); String id = nbtTag.getString("Id"); @@ -216,7 +216,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { if (!block.hasNbtData()) { blocks.add(FaweCache.INSTANCE.asMap("state", index, "pos", pos)); } else { - Map tag = new HashMap<>(block.getNbtData().getValue()); + Map> tag = new HashMap<>(block.getNbtData().getValue()); tag.remove("x"); tag.remove("y"); tag.remove("z"); @@ -246,7 +246,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { BaseEntity state = entity.getState(); if (state != null) { CompoundTag nbt = state.getNbtData(); - Map nbtMap = new HashMap<>(nbt.getValue()); + Map> nbtMap = new HashMap<>(nbt.getValue()); // Replace rotation data nbtMap.put("Rotation", writeRotation(entity.getLocation())); nbtMap.put("id", new StringTag(state.getType().id())); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableEntityChange.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableEntityChange.java index 7fa4ddc6d..b56ebc3eb 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableEntityChange.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableEntityChange.java @@ -3,7 +3,6 @@ package com.fastasyncworldedit.core.history.change; import com.fastasyncworldedit.core.util.MathMan; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.DoubleTag; -import com.sk89q.jnbt.LongTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; @@ -52,7 +51,7 @@ public class MutableEntityChange implements Change { @SuppressWarnings({"unchecked"}) public void delete(UndoContext context) { - Map map = tag.getValue(); + Map> map = tag.getValue(); UUID uuid = tag.getUUID(); if (uuid == null) { LOGGER.info("Skipping entity without uuid."); @@ -66,7 +65,7 @@ public class MutableEntityChange implements Change { } public void create(UndoContext context) { - Map map = tag.getValue(); + Map> map = tag.getValue(); Tag posTag = map.get("Pos"); if (posTag == null) { LOGGER.warn("Missing pos tag: {}", tag); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/BlockBagChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/BlockBagChangeSet.java index c0dc9756c..e17a78765 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/BlockBagChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/BlockBagChangeSet.java @@ -112,7 +112,7 @@ public class BlockBagChangeSet extends AbstractDelegateChangeSet { @Override public void addTileCreate(CompoundTag nbt) { if (nbt.containsKey("items")) { - Map map = new HashMap<>(nbt.getValue()); + Map> map = new HashMap<>(nbt.getValue()); map.remove("items"); } super.addTileCreate(nbt); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/CompressedCompoundTag.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/CompressedCompoundTag.java index 85bdddf09..efed01376 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/CompressedCompoundTag.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/CompressedCompoundTag.java @@ -19,7 +19,7 @@ public abstract class CompressedCompoundTag extends CompoundTag { } @Override - public Map getValue() { + public Map> getValue() { if (in != null) { decompress(); } @@ -36,8 +36,8 @@ public abstract class CompressedCompoundTag extends CompoundTag { try (NBTInputStream nbtIn = new NBTInputStream(adapt(in))) { in = null; CompoundTag tag = (CompoundTag) nbtIn.readTag(); - Map value = tag.getValue(); - Map raw = super.getValue(); + Map> value = tag.getValue(); + Map> raw = super.getValue(); raw.putAll(value); } catch (IOException e) { throw new RuntimeException(e); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/JSON2NBT.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/JSON2NBT.java index 8b942895d..6cdef3dda 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/JSON2NBT.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/JSON2NBT.java @@ -17,7 +17,6 @@ import com.sk89q.jnbt.Tag; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.Stack; import java.util.regex.Pattern; @@ -409,7 +408,7 @@ public class JSON2NBT { } public Tag parse() throws NBTException { - HashMap map = new HashMap<>(); + HashMap> map = new HashMap<>(); for (Any JSON2NBT$any : this.tagList) { map.put(JSON2NBT$any.json, JSON2NBT$any.parse()); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/NumberTag.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/NumberTag.java index db1984bb3..5931069c6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/NumberTag.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/NumberTag.java @@ -1,11 +1,16 @@ package com.fastasyncworldedit.core.jnbt; import com.sk89q.jnbt.Tag; +import org.enginehub.linbus.tree.LinTag; /** * A numerical {@link Tag} */ -public abstract class NumberTag extends Tag { +public abstract class NumberTag> extends Tag { + + protected NumberTag(LT linTag) { + super(linTag); + } @Override public abstract Number getValue(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java index a56fe27d5..534a96fac 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java @@ -124,7 +124,7 @@ public interface IChunkExtent extends Extent { @Override default Entity createEntity(Location location, BaseEntity entity, UUID uuid) { final IChunk chunk = getOrCreateChunk(location.getBlockX() >> 4, location.getBlockZ() >> 4); - Map map = new HashMap<>(entity.getNbtData().getValue()); //do not modify original entity data + Map> map = new HashMap<>(entity.getNbtData().getValue()); //do not modify original entity data map.put("Id", new StringTag(entity.getType().getName())); //Set pos diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/BrushCache.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/BrushCache.java index afab331a7..762929400 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/BrushCache.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/BrushCache.java @@ -82,7 +82,7 @@ public final class BrushCache { } CompoundTag nbt = item.getNbtData(); - Map map; + Map> map; if (nbt == null) { if (tool == null) { item.setNbtData(null); @@ -92,9 +92,10 @@ public final class BrushCache { } else { map = nbt.getValue(); } + item.setNbtData(nbt); brushCache.remove(getKey(item)); CompoundTag display = (CompoundTag) map.get("display"); - Map displayMap; + Map> displayMap; return tool; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java index 7d7d5d642..6b693162e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java @@ -427,7 +427,7 @@ public class MainUtil { */ @Nonnull public static CompoundTag setPosition(@Nonnull CompoundTag tag, int x, int y, int z) { - Map value = new HashMap<>(tag.getValue()); + Map> value = new HashMap<>(tag.getValue()); value.put("x", new IntTag(x)); value.put("y", new IntTag(y)); value.put("z", new IntTag(z)); @@ -443,7 +443,7 @@ public class MainUtil { */ @Nonnull public static CompoundTag setEntityInfo(@Nonnull CompoundTag tag, @Nonnull Entity entity) { - Map map = new HashMap<>(tag.getValue()); + Map> map = new HashMap<>(tag.getValue()); map.put("Id", new StringTag(entity.getState().getType().id())); ListTag pos = (ListTag) map.get("Pos"); if (pos != null) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java index 7abb51284..07157e820 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java @@ -1,13 +1,12 @@ package com.fastasyncworldedit.core.util; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagType; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; -import com.sk89q.worldedit.util.nbt.ByteBinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ShortBinaryTag; import com.sk89q.worldedit.world.storage.InvalidFormatException; +import org.enginehub.linbus.tree.LinByteTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinShortTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import java.util.HashMap; import java.util.Map; @@ -23,9 +22,9 @@ public class NbtUtils { * @return child tag * @throws InvalidFormatException if the format of the items is invalid */ - public static T getChildTag(CompoundBinaryTag tag, String key, BinaryTagType expected) throws + public static T getChildTag(LinCompoundTag tag, String key, LinTagType expected) throws InvalidFormatException { - BinaryTag childTag = tag.get(key); + LinTag childTag = tag.value().get(key); if (childTag == null) { throw new InvalidFormatException("Missing a \"" + key + "\" tag"); } @@ -48,35 +47,35 @@ public class NbtUtils { * @throws InvalidFormatException if the format of the items is invalid * @since 2.1.0 */ - public static int getInt(CompoundBinaryTag tag, String key) throws InvalidFormatException { - BinaryTag childTag = tag.get(key); + public static int getInt(LinCompoundTag tag, String key) throws InvalidFormatException { + LinTag childTag = tag.value().get(key); if (childTag == null) { throw new InvalidFormatException("Missing a \"" + key + "\" tag"); } - BinaryTagType type = childTag.type(); - if (type == BinaryTagTypes.INT) { - return ((IntBinaryTag) childTag).intValue(); + LinTagType type = childTag.type(); + if (type == LinTagType.intTag()) { + return ((LinIntTag) childTag).value(); } - if (type == BinaryTagTypes.BYTE) { - return ((ByteBinaryTag) childTag).intValue(); + if (type == LinTagType.byteTag()) { + return ((LinByteTag) childTag).value(); } - if (type == BinaryTagTypes.SHORT) { - return ((ShortBinaryTag) childTag).intValue(); + if (type == LinTagType.shortTag()) { + return ((LinShortTag) childTag).value(); } throw new InvalidFormatException(key + " tag is not of int, short or byte tag type."); } /** - * Get a mutable map of the values stored inside a {@link CompoundBinaryTag} + * Get a mutable map of the values stored inside a {@link LinCompoundTag} * - * @param tag {@link CompoundBinaryTag} to get values for + * @param tag {@link LinCompoundTag} to get values for * @return Mutable map of values * @since 2.1.0 */ - public static Map getCompoundBinaryTagValues(CompoundBinaryTag tag) { - Map value = new HashMap<>(); - tag.forEach((e) -> value.put(e.getKey(), e.getValue())); + public static Map> getLinCompoundTagValues(LinCompoundTag tag) { + Map> value = new HashMap<>(); + value.putAll(tag.value()); return value; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/BaseItemAdapter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/BaseItemAdapter.java index 859ed9194..9fbdd88bd 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/BaseItemAdapter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/BaseItemAdapter.java @@ -10,9 +10,10 @@ import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.TagStringIO; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; +import org.enginehub.linbus.format.snbt.LinStringIO; +import org.enginehub.linbus.tree.LinCompoundTag; import java.io.IOException; import java.lang.reflect.Type; @@ -36,7 +37,10 @@ public final class BaseItemAdapter implements JsonDeserializer, JsonSe return new BaseItem(itemType); } try { - return new BaseItem(itemType, LazyReference.computed(TagStringIO.get().asCompound(nbt.getAsString()))); + return new BaseItem( + itemType, + LazyReference.computed(LinCompoundTag.readFrom(LinStringIO.readFromString(nbt.getAsString()))) + ); } catch (IOException e) { throw new JsonParseException("Could not deserialize BaseItem", e); } @@ -50,12 +54,8 @@ public final class BaseItemAdapter implements JsonDeserializer, JsonSe ) { JsonObject obj = new JsonObject(); obj.add("itemType", jsonSerializationContext.serialize(baseItem.getType())); - try { - obj.add("nbt", baseItem.getNbt() == null ? null : new JsonPrimitive(TagStringIO.get().asString(baseItem.getNbt()))); - return obj; - } catch (IOException e) { - throw new JsonParseException("Could not deserialize BaseItem", e); - } + obj.add("nbt", baseItem.getNbt() == null ? null : new JsonPrimitive(LinStringIO.writeToString(baseItem.getNbt()))); + return obj; } } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/AdventureNBTConverter.java b/worldedit-core/src/main/java/com/sk89q/jnbt/AdventureNBTConverter.java deleted file mode 100644 index 1e9d36178..000000000 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/AdventureNBTConverter.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.jnbt; - -import com.google.common.collect.BiMap; -import com.google.common.collect.ImmutableBiMap; -import com.google.common.collect.ImmutableMap; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagType; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.Map; -import java.util.Objects; -import java.util.function.Function; - -/** - * Converts between JNBT and Adventure-NBT classes. - * - * @deprecated JNBT is being removed in WE8. - */ -@Deprecated(forRemoval = true) -public class AdventureNBTConverter { - - private static final BiMap, BinaryTagType> TAG_TYPES = - new ImmutableBiMap.Builder, BinaryTagType>() - .put(ByteArrayTag.class, BinaryTagTypes.BYTE_ARRAY) - .put(ByteTag.class, BinaryTagTypes.BYTE) - .put(CompoundTag.class, BinaryTagTypes.COMPOUND) - .put(DoubleTag.class, BinaryTagTypes.DOUBLE) - .put(EndTag.class, BinaryTagTypes.END) - .put(FloatTag.class, BinaryTagTypes.FLOAT) - .put(IntArrayTag.class, BinaryTagTypes.INT_ARRAY) - .put(IntTag.class, BinaryTagTypes.INT) - .put(ListTag.class, BinaryTagTypes.LIST) - .put(LongArrayTag.class, BinaryTagTypes.LONG_ARRAY) - .put(LongTag.class, BinaryTagTypes.LONG) - .put(ShortTag.class, BinaryTagTypes.SHORT) - .put(StringTag.class, BinaryTagTypes.STRING) - .build(); - - private static final Map, Function> CONVERSION; - - static { - ImmutableMap.Builder, Function> conversion = - ImmutableMap.builder(); - - for (Map.Entry, BinaryTagType> tag : TAG_TYPES.entrySet()) { - Constructor[] constructors = tag.getKey().getConstructors(); - for (Constructor c : constructors) { - if (c.getParameterCount() == 1 && BinaryTag.class.isAssignableFrom(c.getParameterTypes()[0])) { - conversion.put(tag.getValue(), binaryTag -> { - try { - return (Tag) c.newInstance(binaryTag); - } catch (InstantiationException | IllegalAccessException e) { - throw new IllegalStateException(e); - } catch (InvocationTargetException e) { - // I assume this is always a RuntimeException since we control the ctor - throw (RuntimeException) e.getCause(); - } - }); - break; - } - } - } - - CONVERSION = conversion.build(); - } - - public static BinaryTagType getAdventureType(Class type) { - return Objects.requireNonNull(TAG_TYPES.get(type), () -> "Missing entry for " + type); - } - - public static Class getJNBTType(BinaryTagType type) { - return Objects.requireNonNull(TAG_TYPES.inverse().get(type), () -> "Missing entry for " + type); - } - - private AdventureNBTConverter() { - } - - public static Tag fromAdventure(BinaryTag other) { - if (other == null) { - return null; - } - Function conversion = CONVERSION.get(other.type()); - if (conversion == null) { - throw new IllegalArgumentException("Can't convert other of type " + other.getClass().getCanonicalName()); - } - return conversion.apply(other); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java index 094a7c9bb..4889235eb 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java @@ -19,41 +19,26 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; +import org.enginehub.linbus.tree.LinByteArrayTag; /** * The {@code TAG_Byte_Array} tag. * - * @deprecated Use {@link ByteArrayBinaryTag}. + * @deprecated Use {@link LinByteArrayTag}. */ @Deprecated -public final class ByteArrayTag extends Tag { - - private final ByteArrayBinaryTag innerTag; - +public final class ByteArrayTag extends Tag { /** * Creates the tag with an empty name. * * @param value the value of the tag */ public ByteArrayTag(byte[] value) { - super(); - this.innerTag = ByteArrayBinaryTag.of(value); + this(LinByteArrayTag.of(value)); } - public ByteArrayTag(ByteArrayBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public byte[] getValue() { - return innerTag.value(); - } - - @Override - public ByteArrayBinaryTag asBinaryTag() { - return innerTag; + public ByteArrayTag(LinByteArrayTag tag) { + super(tag); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java index 6068b2af0..6b3d3d153 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java @@ -19,41 +19,32 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.ByteBinaryTag; +import com.fastasyncworldedit.core.jnbt.NumberTag; +import org.enginehub.linbus.tree.LinByteTag; /** * The {@code TAG_Byte} tag. * - * @deprecated Use {@link ByteBinaryTag}. + * @deprecated Use {@link LinByteTag}. */ @Deprecated -public final class ByteTag extends Tag { - - private final ByteBinaryTag innerTag; - +public final class ByteTag extends NumberTag { /** * Creates the tag with an empty name. * * @param value the value of the tag */ public ByteTag(byte value) { - super(); - this.innerTag = ByteBinaryTag.of(value); + this(LinByteTag.of(value)); } - public ByteTag(ByteBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; + public ByteTag(LinByteTag tag) { + super(tag); } @Override public Byte getValue() { - return innerTag.value(); - } - - @Override - public ByteBinaryTag asBinaryTag() { - return innerTag; + return linTag.value(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java index d91aea8fe..10e9adf08 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java @@ -25,10 +25,11 @@ import com.google.common.collect.Maps; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagLike; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.NumberBinaryTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinNumberTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import java.util.Collections; import java.util.HashMap; @@ -39,26 +40,24 @@ import java.util.UUID; /** * The {@code TAG_Compound} tag. * - * @deprecated Use {@link com.sk89q.worldedit.util.nbt.CompoundBinaryTag}. + * @deprecated Use {@link LinCompoundTag}. */ @Deprecated -public class CompoundTag extends Tag { - - private final CompoundBinaryTag innerTag; +//FAWE start - nonfinal +public class CompoundTag extends Tag { + //FAWE end /** * Creates the tag with an empty name. * * @param value the value of the tag */ - public CompoundTag(Map value) { - this(CompoundBinaryTag.builder() - .put(Maps.transformValues(value, BinaryTagLike::asBinaryTag)) - .build()); + public CompoundTag(Map> value) { + this(LinCompoundTag.of(Maps.transformValues(value, Tag::toLinTag))); } - public CompoundTag(CompoundBinaryTag adventureTag) { - this.innerTag = adventureTag; + public CompoundTag(LinCompoundTag tag) { + super(tag); } /** @@ -68,16 +67,16 @@ public class CompoundTag extends Tag { * @return true if the tag contains the given key */ public boolean containsKey(String key) { - return innerTag.keySet().contains(key); + return linTag.value().containsKey(key); } + @SuppressWarnings({ "unchecked", "rawtypes" }) @Override - public Map getValue() { - ImmutableMap.Builder map = ImmutableMap.builder(); - for (String key : innerTag.keySet()) { - map.put(key, AdventureNBTConverter.fromAdventure(innerTag.get(key))); - } - return map.build(); + public Map> getValue() { + return ImmutableMap.copyOf(Maps.transformValues( + linTag.value(), + tag -> (Tag) LinBusConverter.toJnbtTag((LinTag) tag) + )); } /** @@ -86,7 +85,7 @@ public class CompoundTag extends Tag { * @param value the value * @return the new compound tag */ - public CompoundTag setValue(Map value) { + public CompoundTag setValue(Map> value) { return new CompoundTag(value); } @@ -96,7 +95,7 @@ public class CompoundTag extends Tag { * @return the builder */ public CompoundTagBuilder createBuilder() { - return new CompoundTagBuilder(innerTag); + return new CompoundTagBuilder(linTag); } /** @@ -109,7 +108,8 @@ public class CompoundTag extends Tag { * @return a byte array */ public byte[] getByteArray(String key) { - return this.innerTag.getByteArray(key); + var tag = linTag.findTag(key, LinTagType.byteArrayTag()); + return tag == null ? new byte[0] : tag.value(); } /** @@ -122,7 +122,8 @@ public class CompoundTag extends Tag { * @return a byte */ public byte getByte(String key) { - return this.innerTag.getByte(key); + var tag = linTag.findTag(key, LinTagType.byteTag()); + return tag == null ? 0 : tag.value(); } /** @@ -135,7 +136,8 @@ public class CompoundTag extends Tag { * @return a double */ public double getDouble(String key) { - return this.innerTag.getDouble(key); + var tag = linTag.findTag(key, LinTagType.doubleTag()); + return tag == null ? 0 : tag.value(); } /** @@ -149,9 +151,10 @@ public class CompoundTag extends Tag { * @return a double */ public double asDouble(String key) { - BinaryTag tag = this.innerTag.get(key); - if (tag instanceof NumberBinaryTag) { - return ((NumberBinaryTag) tag).doubleValue(); + var tag = linTag.value().get(key); + if (tag instanceof LinNumberTag numberTag) { + Number value = numberTag.value(); + return value.doubleValue(); } return 0; } @@ -166,7 +169,8 @@ public class CompoundTag extends Tag { * @return a float */ public float getFloat(String key) { - return this.innerTag.getFloat(key); + var tag = linTag.findTag(key, LinTagType.floatTag()); + return tag == null ? 0 : tag.value(); } /** @@ -179,7 +183,8 @@ public class CompoundTag extends Tag { * @return an int array */ public int[] getIntArray(String key) { - return this.innerTag.getIntArray(key); + var tag = linTag.findTag(key, LinTagType.intArrayTag()); + return tag == null ? new int[0] : tag.value(); } /** @@ -192,7 +197,8 @@ public class CompoundTag extends Tag { * @return an int */ public int getInt(String key) { - return this.innerTag.getInt(key); + var tag = linTag.findTag(key, LinTagType.intTag()); + return tag == null ? 0 : tag.value(); } /** @@ -206,9 +212,10 @@ public class CompoundTag extends Tag { * @return an int */ public int asInt(String key) { - BinaryTag tag = this.innerTag.get(key); - if (tag instanceof NumberBinaryTag) { - return ((NumberBinaryTag) tag).intValue(); + var tag = linTag.value().get(key); + if (tag instanceof LinNumberTag numberTag) { + Number value = numberTag.value(); + return value.intValue(); } return 0; } @@ -222,7 +229,7 @@ public class CompoundTag extends Tag { * @param key the key * @return a list of tags */ - public List getList(String key) { + public List> getList(String key) { return getListTag(key).getValue(); } @@ -235,8 +242,15 @@ public class CompoundTag extends Tag { * @param key the key * @return a tag list instance */ - public ListTag getListTag(String key) { - return new ListTag(this.innerTag.getList(key)); + public > ListTag getListTag(String key) { + LinListTag tag = linTag.findTag(key, LinTagType.listTag()); + if (tag == null) { + // This is actually hella unsafe. But eh. + @SuppressWarnings("unchecked") + LinTagType endGenerically = (LinTagType) LinTagType.endTag(); + return new ListTag<>(LinListTag.empty(endGenerically)); + } + return new ListTag<>(tag); } /** @@ -253,8 +267,8 @@ public class CompoundTag extends Tag { * @return a list of tags */ @SuppressWarnings("unchecked") - public List getList(String key, Class listType) { - ListTag listTag = getListTag(key); + public > List getList(String key, Class listType) { + ListTag listTag = getListTag(key); if (listTag.getType().equals(listType)) { return (List) listTag.getValue(); } else { @@ -272,7 +286,8 @@ public class CompoundTag extends Tag { * @return an int array */ public long[] getLongArray(String key) { - return this.innerTag.getLongArray(key); + var tag = linTag.findTag(key, LinTagType.longArrayTag()); + return tag == null ? new long[0] : tag.value(); } /** @@ -285,7 +300,8 @@ public class CompoundTag extends Tag { * @return a long */ public long getLong(String key) { - return this.innerTag.getLong(key); + var tag = linTag.findTag(key, LinTagType.longTag()); + return tag == null ? 0 : tag.value(); } /** @@ -299,9 +315,10 @@ public class CompoundTag extends Tag { * @return a long */ public long asLong(String key) { - BinaryTag tag = this.innerTag.get(key); - if (tag instanceof NumberBinaryTag) { - return ((NumberBinaryTag) tag).longValue(); + var tag = linTag.value().get(key); + if (tag instanceof LinNumberTag numberTag) { + Number value = numberTag.value(); + return value.longValue(); } return 0; } @@ -316,7 +333,8 @@ public class CompoundTag extends Tag { * @return a short */ public short getShort(String key) { - return this.innerTag.getShort(key); + var tag = linTag.findTag(key, LinTagType.shortTag()); + return tag == null ? 0 : tag.value(); } /** @@ -329,12 +347,8 @@ public class CompoundTag extends Tag { * @return a string */ public String getString(String key) { - return this.innerTag.getString(key); - } - - @Override - public CompoundBinaryTag asBinaryTag() { - return this.innerTag; + var tag = linTag.findTag(key, LinTagType.stringTag()); + return tag == null ? "" : tag.value(); } @@ -357,7 +371,7 @@ public class CompoundTag extends Tag { } public Vector3 getEntityPosition() { - List posTags = getList("Pos"); + List> posTags = getList("Pos"); double x = ((NumberTag) posTags.get(0)).getValue().doubleValue(); double y = ((NumberTag) posTags.get(1)).getValue().doubleValue(); double z = ((NumberTag) posTags.get(2)).getValue().doubleValue(); @@ -365,7 +379,7 @@ public class CompoundTag extends Tag { } public Location getEntityLocation(Extent extent) { - List rotTag = getList("Rotation"); + List> rotTag = getList("Rotation"); float yaw = ((NumberTag) rotTag.get(0)).getValue().floatValue(); float pitch = ((NumberTag) rotTag.get(1)).getValue().floatValue(); return new Location(extent, getEntityPosition(), yaw, pitch); @@ -382,7 +396,7 @@ public class CompoundTag extends Tag { if (this.getValue().isEmpty()) { return raw; } - for (Map.Entry entry : getValue().entrySet()) { + for (Map.Entry> entry : getValue().entrySet()) { raw.put(entry.getKey(), entry.getValue().toRaw()); } return raw; diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java index f21bdb8cc..535722b74 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java @@ -19,27 +19,27 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import org.enginehub.linbus.tree.LinCompoundTag; import java.util.Map; -import java.util.Objects; import static com.google.common.base.Preconditions.checkNotNull; /** * Helps create compound tags. * - * @deprecated Use {@link com.sk89q.worldedit.util.nbt.CompoundBinaryTag.Builder}. + * @deprecated Use {@link LinCompoundTag.Builder}. */ @Deprecated public class CompoundTagBuilder { - private final CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + private final LinCompoundTag.Builder builder; /** * Create a new instance. */ CompoundTagBuilder() { + this.builder = LinCompoundTag.builder(); } /** @@ -47,11 +47,9 @@ public class CompoundTagBuilder { * * @param source the value */ - CompoundTagBuilder(CompoundBinaryTag source) { + CompoundTagBuilder(LinCompoundTag source) { checkNotNull(source); - for (String key : source.keySet()) { - this.builder.put(key, Objects.requireNonNull(source.get(key))); - } + this.builder = source.toBuilder(); } /** @@ -61,10 +59,10 @@ public class CompoundTagBuilder { * @param value the value * @return this object */ - public CompoundTagBuilder put(String key, Tag value) { + public CompoundTagBuilder put(String key, Tag value) { checkNotNull(key); checkNotNull(value); - this.builder.put(key, value.asBinaryTag()); + this.builder.put(key, value.toLinTag()); return this; } @@ -215,9 +213,9 @@ public class CompoundTagBuilder { * @param value the map of tags * @return this object */ - public CompoundTagBuilder putAll(Map value) { + public CompoundTagBuilder putAll(Map> value) { checkNotNull(value); - for (Map.Entry entry : value.entrySet()) { + for (Map.Entry> entry : value.entrySet()) { put(entry.getKey(), entry.getValue()); } return this; diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java index da0890ea6..6dad5186b 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java @@ -20,17 +20,15 @@ package com.sk89q.jnbt; import com.fastasyncworldedit.core.jnbt.NumberTag; -import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; +import org.enginehub.linbus.tree.LinDoubleTag; /** * The {@code TAG_Double} tag. * - * @deprecated Use {@link DoubleBinaryTag}. + * @deprecated Use {@link LinDoubleTag}. */ @Deprecated -public final class DoubleTag extends NumberTag { - - private final DoubleBinaryTag innerTag; +public final class DoubleTag extends NumberTag { /** * Creates the tag with an empty name. @@ -38,23 +36,16 @@ public final class DoubleTag extends NumberTag { * @param value the value of the tag */ public DoubleTag(double value) { - super(); - this.innerTag = DoubleBinaryTag.of(value); + this(LinDoubleTag.of(value)); } - public DoubleTag(DoubleBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public DoubleBinaryTag asBinaryTag() { - return this.innerTag; + public DoubleTag(LinDoubleTag tag) { + super(tag); } @Override public Double getValue() { - return innerTag.value(); + return linTag.value(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/EndTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/EndTag.java index 18347d928..523fcf79e 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/EndTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/EndTag.java @@ -19,24 +19,17 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.EndBinaryTag; +import org.enginehub.linbus.tree.LinEndTag; /** * The {@code TAG_End} tag. * - * @deprecated Use {@link com.sk89q.worldedit.util.nbt.EndBinaryTag}. + * @deprecated Use {@link LinEndTag}. */ @Deprecated -public final class EndTag extends Tag { - - @Override - public Object getValue() { - return null; - } - - @Override - public EndBinaryTag asBinaryTag() { - return EndBinaryTag.get(); +public final class EndTag extends Tag { + public EndTag() { + super(LinEndTag.instance()); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java index 2e1533827..128e36014 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java @@ -20,17 +20,14 @@ package com.sk89q.jnbt; import com.fastasyncworldedit.core.jnbt.NumberTag; -import com.sk89q.worldedit.util.nbt.FloatBinaryTag; +import org.enginehub.linbus.tree.LinFloatTag; /** * The {@code TAG_Float} tag. * - * @deprecated Use {@link FloatBinaryTag}. + * @deprecated Use {@link LinFloatTag}. */ -@Deprecated -public final class FloatTag extends NumberTag { - - private final FloatBinaryTag innerTag; +public final class FloatTag extends NumberTag { /** * Creates the tag with an empty name. @@ -38,23 +35,16 @@ public final class FloatTag extends NumberTag { * @param value the value of the tag */ public FloatTag(float value) { - super(); - this.innerTag = FloatBinaryTag.of(value); + this(LinFloatTag.of(value)); } - public FloatTag(FloatBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public FloatBinaryTag asBinaryTag() { - return this.innerTag; + public FloatTag(LinFloatTag tag) { + super(tag); } @Override public Float getValue() { - return innerTag.value(); + return linTag.value(); } //FAWE start 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 76d8fac74..0e3536eed 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/IntArrayTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/IntArrayTag.java @@ -19,44 +19,33 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; +import org.enginehub.linbus.tree.LinIntArrayTag; import static com.google.common.base.Preconditions.checkNotNull; /** * The {@code TAG_Int_Array} tag. * - * @deprecated Use {@link IntArrayBinaryTag}. + * @deprecated Use {@link LinIntArrayTag}. */ @Deprecated -public final class IntArrayTag extends Tag { - - private final IntArrayBinaryTag innerTag; - +public final class IntArrayTag extends Tag { /** * Creates the tag with an empty name. * * @param value the value of the tag */ public IntArrayTag(int[] value) { - super(); - checkNotNull(value); - this.innerTag = IntArrayBinaryTag.of(value); + this(LinIntArrayTag.of(checkNotNull(value))); } - public IntArrayTag(IntArrayBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public IntArrayBinaryTag asBinaryTag() { - return this.innerTag; + public IntArrayTag(LinIntArrayTag tag) { + super(tag); } @Override public int[] getValue() { - return innerTag.value(); + return linTag.value(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java index c6ff80252..c4c90889b 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java @@ -19,17 +19,16 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; +import com.fastasyncworldedit.core.jnbt.NumberTag; +import org.enginehub.linbus.tree.LinIntTag; /** * The {@code TAG_Int} tag. * - * @deprecated Use {@link IntBinaryTag}. + * @deprecated Use {@link LinIntTag}. */ @Deprecated -public final class IntTag extends Tag { - - private final IntBinaryTag innerTag; +public final class IntTag extends NumberTag { /** * Creates the tag with an empty name. @@ -37,23 +36,16 @@ public final class IntTag extends Tag { * @param value the value of the tag */ public IntTag(int value) { - super(); - this.innerTag = IntBinaryTag.of(value); + this(LinIntTag.of(value)); } - public IntTag(IntBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public IntBinaryTag asBinaryTag() { - return this.innerTag; + public IntTag(LinIntTag tag) { + super(tag); } @Override public Integer getValue() { - return innerTag.value(); + return linTag.value(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/LazyCompoundTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/LazyCompoundTag.java index 00b5aeb9a..4ce6febd6 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/LazyCompoundTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/LazyCompoundTag.java @@ -20,27 +20,27 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import org.enginehub.linbus.tree.LinCompoundTag; import java.util.Map; /** * Allows detection of the version-specific LazyCompoundTag classes. * - * @deprecated Use {@link CompoundBinaryTag}. + * @deprecated Use {@link LinCompoundTag}. */ @Deprecated public abstract class LazyCompoundTag extends CompoundTag { - public LazyCompoundTag(Map value) { + public LazyCompoundTag(Map> value) { super(value); } - public LazyCompoundTag(CompoundBinaryTag adventureTag) { + public LazyCompoundTag(LinCompoundTag adventureTag) { super(adventureTag); } @Override - public abstract CompoundBinaryTag asBinaryTag(); + public abstract LinCompoundTag toLinTag(); } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/LinBusConverter.java b/worldedit-core/src/main/java/com/sk89q/jnbt/LinBusConverter.java new file mode 100644 index 000000000..52b30f599 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/LinBusConverter.java @@ -0,0 +1,140 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.jnbt; + +import com.google.common.collect.BiMap; +import com.google.common.collect.ImmutableBiMap; +import com.google.common.collect.ImmutableMap; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinByteTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinLongArrayTag; +import org.enginehub.linbus.tree.LinLongTag; +import org.enginehub.linbus.tree.LinShortTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; + +/** + * Converts between JNBT and Adventure-NBT classes. + * + * @deprecated JNBT is being removed in WE8. + */ +@Deprecated(forRemoval = true) +public class LinBusConverter { + + private static final BiMap, LinTagType> TAG_TYPES = + new ImmutableBiMap.Builder, LinTagType>() + .put(ByteArrayTag.class, LinTagType.byteArrayTag()) + .put(ByteTag.class, LinTagType.byteTag()) + .put(CompoundTag.class, LinTagType.compoundTag()) + .put(DoubleTag.class, LinTagType.doubleTag()) + .put(EndTag.class, LinTagType.endTag()) + .put(FloatTag.class, LinTagType.floatTag()) + .put(IntArrayTag.class, LinTagType.intArrayTag()) + .put(IntTag.class, LinTagType.intTag()) + .put(ListTag.class, LinTagType.listTag()) + .put(LongArrayTag.class, LinTagType.longArrayTag()) + .put(LongTag.class, LinTagType.longTag()) + .put(ShortTag.class, LinTagType.shortTag()) + .put(StringTag.class, LinTagType.stringTag()) + .build(); + + private static final Map, Function> CONVERSION; + + static { + ImmutableMap.Builder, Function> conversion = + ImmutableMap.builder(); + + for (Map.Entry, LinTagType> tag : TAG_TYPES.entrySet()) { + Constructor[] constructors = tag.getKey().getConstructors(); + for (Constructor c : constructors) { + if (c.getParameterCount() == 1 && LinTag.class.isAssignableFrom(c.getParameterTypes()[0])) { + conversion.put(tag.getValue(), linTag -> { + try { + return (Tag) c.newInstance(linTag); + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalStateException(e); + } catch (InvocationTargetException e) { + // I assume this is always a RuntimeException since we control the ctor + throw (RuntimeException) e.getCause(); + } + }); + break; + } + } + } + + CONVERSION = conversion.build(); + } + + public static LinTagType getAdventureType(Class type) { + return Objects.requireNonNull(TAG_TYPES.get(type), () -> "Missing entry for " + type); + } + + public static Class getJNBTType(LinTagType type) { + return Objects.requireNonNull(TAG_TYPES.inverse().get(type), () -> "Missing entry for " + type); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static > Tag toJnbtTag(LT tag) { + return (Tag) switch (tag.type().id()) { + case BYTE_ARRAY -> new ByteArrayTag((LinByteArrayTag) tag); + case BYTE -> new ByteTag((LinByteTag) tag); + case COMPOUND -> new CompoundTag((LinCompoundTag) tag); + case DOUBLE -> new DoubleTag((LinDoubleTag) tag); + case END -> new EndTag(); + case FLOAT -> new FloatTag((LinFloatTag) tag); + case INT_ARRAY -> new IntArrayTag((LinIntArrayTag) tag); + case INT -> new IntTag((LinIntTag) tag); + case LIST -> new ListTag((LinListTag) tag); + case LONG_ARRAY -> new LongArrayTag((LinLongArrayTag) tag); + case LONG -> new LongTag((LinLongTag) tag); + case SHORT -> new ShortTag((LinShortTag) tag); + case STRING -> new StringTag((LinStringTag) tag); + }; + } + + private LinBusConverter() { + } + + public static Tag fromLinBus(LinTag other) { + if (other == null) { + return null; + } + Function conversion = CONVERSION.get(other.type()); + if (conversion == null) { + throw new IllegalArgumentException("Can't convert other of type " + other.getClass().getCanonicalName()); + } + return conversion.apply(other); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java index 879a0d4a3..d3c330d4d 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java @@ -19,10 +19,20 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagLike; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; -import com.sk89q.worldedit.util.nbt.NumberBinaryTag; +import org.enginehub.linbus.common.LinTagId; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinByteTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinLongTag; +import org.enginehub.linbus.tree.LinNumberTag; +import org.enginehub.linbus.tree.LinShortTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import javax.annotation.Nullable; import java.util.Collections; @@ -34,12 +44,10 @@ import java.util.stream.Collectors; /** * The {@code TAG_List} tag. * - * @deprecated Use {@link com.sk89q.worldedit.util.nbt.ListBinaryTag}. + * @deprecated Use {@link LinListTag}. */ @Deprecated -public final class ListTag extends Tag { - - private final ListBinaryTag innerTag; +public final class ListTag> extends Tag> { /** * Creates the tag with an empty name. @@ -47,20 +55,15 @@ public final class ListTag extends Tag { * @param type the type of tag * @param value the value of the tag */ - public ListTag(Class type, List value) { - this(ListBinaryTag.of( - AdventureNBTConverter.getAdventureType(type), - value.stream().map(BinaryTagLike::asBinaryTag).collect(Collectors.toList()) + public ListTag(Class> type, List> value) { + this(LinListTag.of( + LinTagType.fromId(LinTagId.fromId(NBTUtils.getTypeCode(type))), + value.stream().map(Tag::toLinTag).collect(Collectors.toList()) )); } - public ListTag(ListBinaryTag adventureTag) { - this.innerTag = adventureTag; - } - - @Override - public ListBinaryTag asBinaryTag() { - return this.innerTag; + public ListTag(LinListTag tag) { + super(tag); } /** @@ -68,15 +71,14 @@ public final class ListTag extends Tag { * * @return The type of item in this list. */ - public Class getType() { - return AdventureNBTConverter.getJNBTType(this.innerTag.elementType()); + @SuppressWarnings("unchecked") + public Class> getType() { + return (Class>) NBTUtils.getTypeClass(linTag.elementType().id().id()); } @Override - public List getValue() { - return this.innerTag.stream() - .map(AdventureNBTConverter::fromAdventure) - .collect(Collectors.toList()); + public List> getValue() { + return linTag.value().stream().map(LinBusConverter::toJnbtTag).toList(); } /** @@ -85,17 +87,31 @@ public final class ListTag extends Tag { * @param list the new list * @return a new list tag */ - public ListTag setValue(List list) { - return new ListTag(getType(), list); + public ListTag setValue(List> list) { + return new ListTag<>(getType(), list); } private T accessIfExists(int index, Supplier defaultValue, IntFunction accessor) { - if (index >= this.innerTag.size()) { + if (index >= this.linTag.value().size()) { return defaultValue.get(); } return accessor.apply(index); } + @SuppressWarnings("unchecked") + private > T extractViaValue( + int index, Class requiredType, Supplier defaultValue + ) { + if (index >= this.linTag.value().size()) { + return defaultValue.get(); + } + E value = this.linTag.get(index); + if (!requiredType.isInstance(value)) { + return defaultValue.get(); + } + return (T) value.value(); + } + /** * Get the tag if it exists at the given index. * @@ -103,11 +119,11 @@ public final class ListTag extends Tag { * @return the tag or null */ @Nullable - public Tag getIfExists(int index) { + public Tag getIfExists(int index) { return accessIfExists( - index, - () -> null, - i -> AdventureNBTConverter.fromAdventure(this.innerTag.get(i)) + index, + () -> null, + i -> LinBusConverter.toJnbtTag(this.linTag.get(i)) ); } @@ -121,11 +137,7 @@ public final class ListTag extends Tag { * @return a byte array */ public byte[] getByteArray(int index) { - return accessIfExists( - index, - () -> new byte[0], - this.innerTag::getByteArray - ); + return extractViaValue(index, LinByteArrayTag.class, () -> new byte[0]); } /** @@ -138,11 +150,7 @@ public final class ListTag extends Tag { * @return a byte */ public byte getByte(int index) { - return accessIfExists( - index, - () -> (byte) 0, - this.innerTag::getByte - ); + return extractViaValue(index, LinByteTag.class, () -> (byte) 0); } /** @@ -155,11 +163,7 @@ public final class ListTag extends Tag { * @return a double */ public double getDouble(int index) { - return accessIfExists( - index, - () -> 0.0, - this.innerTag::getDouble - ); + return extractViaValue(index, LinDoubleTag.class, () -> 0.0); } /** @@ -174,15 +178,11 @@ public final class ListTag extends Tag { */ public double asDouble(int index) { return accessIfExists( - index, - () -> 0.0, - i -> { - BinaryTag tag = this.innerTag.get(i); - if (tag instanceof NumberBinaryTag) { - return ((NumberBinaryTag) tag).doubleValue(); - } - return 0.0; - } + index, + () -> 0.0, + i -> this.linTag.get(i) instanceof LinNumberTag tag + ? tag.value().doubleValue() + : 0.0 ); } @@ -196,11 +196,7 @@ public final class ListTag extends Tag { * @return a float */ public float getFloat(int index) { - return accessIfExists( - index, - () -> 0.0f, - this.innerTag::getFloat - ); + return extractViaValue(index, LinFloatTag.class, () -> 0f); } /** @@ -213,11 +209,7 @@ public final class ListTag extends Tag { * @return an int array */ public int[] getIntArray(int index) { - return accessIfExists( - index, - () -> new int[0], - this.innerTag::getIntArray - ); + return extractViaValue(index, LinIntArrayTag.class, () -> new int[0]); } /** @@ -230,11 +222,7 @@ public final class ListTag extends Tag { * @return an int */ public int getInt(int index) { - return accessIfExists( - index, - () -> 0, - this.innerTag::getInt - ); + return extractViaValue(index, LinIntTag.class, () -> 0); } /** @@ -249,15 +237,11 @@ public final class ListTag extends Tag { */ public int asInt(int index) { return accessIfExists( - index, - () -> 0, - i -> { - BinaryTag tag = this.innerTag.get(i); - if (tag instanceof NumberBinaryTag) { - return ((NumberBinaryTag) tag).intValue(); - } - return 0; - } + index, + () -> 0, + i -> this.linTag.get(i) instanceof LinNumberTag tag + ? tag.value().intValue() + : 0 ); } @@ -270,7 +254,7 @@ public final class ListTag extends Tag { * @param index the index * @return a list of tags */ - public List getList(int index) { + public List> getList(int index) { return getListTag(index).getValue(); } @@ -283,11 +267,12 @@ public final class ListTag extends Tag { * @param index the index * @return a tag list instance */ - public ListTag getListTag(int index) { - return new ListTag(accessIfExists( - index, - ListBinaryTag::empty, - this.innerTag::getList + @SuppressWarnings("unchecked") + public ListTag getListTag(int index) { + return new ListTag<>(extractViaValue( + index, + LinListTag.class, + () -> LinListTag.empty(LinTagType.endTag()) )); } @@ -305,8 +290,8 @@ public final class ListTag extends Tag { * @return a list of tags */ @SuppressWarnings("unchecked") - public List getList(int index, Class listType) { - ListTag listTag = getListTag(index); + public > List getList(int index, Class listType) { + ListTag listTag = getListTag(index); if (listTag.getType().equals(listType)) { return (List) listTag.getValue(); } else { @@ -324,11 +309,7 @@ public final class ListTag extends Tag { * @return a long */ public long getLong(int index) { - return accessIfExists( - index, - () -> 0L, - this.innerTag::getLong - ); + return extractViaValue(index, LinLongTag.class, () -> 0L); } /** @@ -343,15 +324,11 @@ public final class ListTag extends Tag { */ public long asLong(int index) { return accessIfExists( - index, - () -> 0L, - i -> { - BinaryTag tag = this.innerTag.get(i); - if (tag instanceof NumberBinaryTag) { - return ((NumberBinaryTag) tag).longValue(); - } - return 0L; - } + index, + () -> 0L, + i -> this.linTag.get(i) instanceof LinNumberTag tag + ? tag.value().longValue() + : 0L ); } @@ -365,11 +342,7 @@ public final class ListTag extends Tag { * @return a short */ public short getShort(int index) { - return accessIfExists( - index, - () -> (short) 0, - this.innerTag::getShort - ); + return extractViaValue(index, LinShortTag.class, () -> (short) 0); } /** @@ -382,11 +355,7 @@ public final class ListTag extends Tag { * @return a string */ public String getString(int index) { - return accessIfExists( - index, - () -> "", - this.innerTag::getString - ); + return extractViaValue(index, LinStringTag.class, () -> ""); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ListTagBuilder.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ListTagBuilder.java index 78a8b6401..18aab079c 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ListTagBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ListTagBuilder.java @@ -19,11 +19,11 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagType; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; +import org.enginehub.linbus.common.LinTagId; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; -import java.util.Arrays; import java.util.Collection; import static com.google.common.base.Preconditions.checkNotNull; @@ -31,12 +31,12 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Helps create list tags. * - * @deprecated Use {@link com.sk89q.worldedit.util.nbt.ListBinaryTag.Builder}. + * @deprecated Use {@link LinListTag.Builder}. */ @Deprecated -public class ListTagBuilder { +public class ListTagBuilder> { - private final ListBinaryTag.Builder builder; + private final LinListTag.Builder builder; /** * Create a new instance. @@ -44,11 +44,11 @@ public class ListTagBuilder { * @param type of tag contained in this list */ @SuppressWarnings("unchecked") - ListTagBuilder(Class type) { + ListTagBuilder(Class> type) { checkNotNull(type); - this.builder = type != EndTag.class - ? ListBinaryTag.builder((BinaryTagType) AdventureNBTConverter.getAdventureType(type)) - : ListBinaryTag.builder(); + this.builder = (LinListTag.Builder) LinListTag.builder(LinTagType.fromId(LinTagId.fromId( + NBTUtils.getTypeCode(type) + ))); } /** @@ -57,9 +57,9 @@ public class ListTagBuilder { * @param value the tag * @return this object */ - public ListTagBuilder add(Tag value) { + public ListTagBuilder add(Tag value) { checkNotNull(value); - builder.add(value.asBinaryTag()); + builder.add(value.toLinTag()); return this; } @@ -69,9 +69,9 @@ public class ListTagBuilder { * @param value a list of tags * @return this object */ - public ListTagBuilder addAll(Collection value) { + public ListTagBuilder addAll(Collection> value) { checkNotNull(value); - for (Tag v : value) { + for (Tag v : value) { add(v); } return this; @@ -82,8 +82,8 @@ public class ListTagBuilder { * * @return the new list tag */ - public ListTag build() { - return new ListTag(this.builder.build()); + public ListTag build() { + return new ListTag<>(this.builder.build()); } /** @@ -91,8 +91,8 @@ public class ListTagBuilder { * * @return a new builder */ - public static ListTagBuilder create(Class type) { - return new ListTagBuilder(type); + public static > ListTagBuilder create(Class> type) { + return new ListTagBuilder<>(type); } /** @@ -100,22 +100,24 @@ public class ListTagBuilder { * * @return a new builder */ - public static ListTagBuilder createWith(Tag... entries) { + @SafeVarargs + public static > ListTagBuilder createWith(Tag... entries) { checkNotNull(entries); if (entries.length == 0) { throw new IllegalArgumentException("This method needs an array of at least one entry"); } - Class type = entries[0].getClass(); - for (int i = 1; i < entries.length; i++) { - if (!type.isInstance(entries[i])) { + @SuppressWarnings("unchecked") + Class> type = (Class>) entries[0].getClass(); + ListTagBuilder builder = new ListTagBuilder<>(type); + for (Tag entry : entries) { + if (!type.isInstance(entry)) { throw new IllegalArgumentException("An array of different tag types was provided"); } + builder.add(entry); } - ListTagBuilder builder = new ListTagBuilder(type); - builder.addAll(Arrays.asList(entries)); return builder; } 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 81c6e3376..968019b7e 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/LongArrayTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/LongArrayTag.java @@ -19,44 +19,33 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; +import org.enginehub.linbus.tree.LinLongArrayTag; import static com.google.common.base.Preconditions.checkNotNull; /** * The {@code TAG_Long_Array} tag. * - * @deprecated Use {@link LongArrayBinaryTag}. + * @deprecated Use {@link LinLongArrayTag}. */ @Deprecated -public class LongArrayTag extends Tag { - - private final LongArrayBinaryTag innerTag; - +public class LongArrayTag extends Tag { /** * Creates the tag with an empty name. * * @param value the value of the tag */ public LongArrayTag(long[] value) { - super(); - checkNotNull(value); - this.innerTag = LongArrayBinaryTag.of(value); + this(LinLongArrayTag.of(checkNotNull(value))); } - public LongArrayTag(LongArrayBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public LongArrayBinaryTag asBinaryTag() { - return this.innerTag; + public LongArrayTag(LinLongArrayTag tag) { + super(tag); } @Override public long[] getValue() { - return innerTag.value(); + return linTag.value(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java index 84a443746..b8632b752 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java @@ -19,41 +19,32 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.LongBinaryTag; +import com.fastasyncworldedit.core.jnbt.NumberTag; +import org.enginehub.linbus.tree.LinLongTag; /** * The {@code TAG_Long} tag. * - * @deprecated Use {@link LongBinaryTag}. + * @deprecated Use {@link LinLongTag}. */ @Deprecated -public final class LongTag extends Tag { - - private final LongBinaryTag innerTag; - +public final class LongTag extends NumberTag { /** * Creates the tag with an empty name. * * @param value the value of the tag */ public LongTag(long value) { - super(); - this.innerTag = LongBinaryTag.of(value); + this(LinLongTag.of(value)); } - public LongTag(LongBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public LongBinaryTag asBinaryTag() { - return this.innerTag; + public LongTag(LinLongTag tag) { + super(tag); } @Override public Long getValue() { - return innerTag.value(); + return linTag.value(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java index 54746fc49..3ab1923c1 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java @@ -50,7 +50,6 @@ public final class NBTConstants { * Default private constructor. */ private NBTConstants() { - } /** @@ -60,37 +59,27 @@ public final class NBTConstants { * @return tag class * @throws IllegalArgumentException thrown if the tag ID is not valid */ - public static Class getClassFromType(int id) { - switch (id) { - case TYPE_END: - return EndTag.class; - case TYPE_BYTE: - return ByteTag.class; - case TYPE_SHORT: - return ShortTag.class; - case TYPE_INT: - return IntTag.class; - case TYPE_LONG: - return LongTag.class; - case TYPE_FLOAT: - return FloatTag.class; - case TYPE_DOUBLE: - return DoubleTag.class; - case TYPE_BYTE_ARRAY: - return ByteArrayTag.class; - case TYPE_STRING: - return StringTag.class; - case TYPE_LIST: - return ListTag.class; - case TYPE_COMPOUND: - return CompoundTag.class; - case TYPE_INT_ARRAY: - return IntArrayTag.class; - case TYPE_LONG_ARRAY: - return LongArrayTag.class; - default: - throw new IllegalArgumentException("Unknown tag type ID of " + id); - } + public static Class> getClassFromType(int id) { + return switch (id) { + case TYPE_END -> EndTag.class; + case TYPE_BYTE -> ByteTag.class; + case TYPE_SHORT -> ShortTag.class; + case TYPE_INT -> IntTag.class; + case TYPE_LONG -> LongTag.class; + case TYPE_FLOAT -> FloatTag.class; + case TYPE_DOUBLE -> DoubleTag.class; + case TYPE_BYTE_ARRAY -> ByteArrayTag.class; + case TYPE_STRING -> StringTag.class; + case TYPE_LIST -> { + @SuppressWarnings("unchecked") + var aClass = (Class>) (Class) ListTag.class; + yield aClass; + } + case TYPE_COMPOUND -> CompoundTag.class; + case TYPE_INT_ARRAY -> IntArrayTag.class; + case TYPE_LONG_ARRAY -> LongArrayTag.class; + default -> throw new IllegalArgumentException("Unknown tag type ID of " + id); + }; } } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java index fca025212..806168327 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java @@ -21,6 +21,7 @@ package com.sk89q.jnbt; import com.fastasyncworldedit.core.jnbt.streamer.StreamDelegate; import com.fastasyncworldedit.core.jnbt.streamer.ValueReader; +import org.enginehub.linbus.stream.LinBinaryIO; import java.io.Closeable; import java.io.DataInputStream; @@ -44,8 +45,9 @@ import java.util.Map; * https://minecraft.gamepedia.com/NBT_format. *

    * - * @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8. + * @deprecated JNBT is being removed for lin-bus in WorldEdit 8, use {@link LinBinaryIO} instead */ +@SuppressWarnings("removal") @Deprecated(forRemoval = true) public final class NBTInputStream implements Closeable { @@ -77,7 +79,6 @@ public final class NBTInputStream implements Closeable { * Reads an NBT tag from the stream. * * @return The tag that was read. - * @throws IOException if an I/O error occurs. */ public NamedTag readNamedTag() throws IOException { return readNamedTag(0); @@ -617,7 +618,7 @@ public final class NBTInputStream implements Closeable { return new ListTag(NBTUtils.getTypeClass(childType), tagList); case NBTConstants.TYPE_COMPOUND: - Map tagMap = new HashMap<>(); + Map> tagMap = new HashMap<>(); while (true) { NamedTag namedTag = readNamedTag(depth + 1); Tag tag = namedTag.getTag(); diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java index 6342455eb..b466e6de2 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java @@ -20,6 +20,7 @@ package com.sk89q.jnbt; import com.fastasyncworldedit.core.internal.io.LittleEndianOutputStream; +import org.enginehub.linbus.stream.LinBinaryIO; import java.io.Closeable; import java.io.DataOutput; @@ -44,8 +45,9 @@ import static com.google.common.base.Preconditions.checkNotNull; * https://minecraft.gamepedia.com/NBT_format. *

    * - * @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8. + * @deprecated JNBT is being removed for lin-bus in WorldEdit 8, use {@link LinBinaryIO} instead */ +@SuppressWarnings("removal") @Deprecated(forRemoval = true) public final class NBTOutputStream extends OutputStream implements Closeable, DataOutput { @@ -61,7 +63,7 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da * @param os The output stream. * @throws IOException if an I/O error occurs. */ - public NBTOutputStream(OutputStream os) throws IOException { + public NBTOutputStream(OutputStream os) { this(os instanceof DataOutput ? (DataOutput) os : new DataOutputStream(os)); } @@ -91,11 +93,11 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da * @param tag The tag to write. * @throws IOException if an I/O error occurs. */ - public void writeNamedTag(String name, Tag tag) throws IOException { + public void writeNamedTag(String name, Tag tag) throws IOException { checkNotNull(name); checkNotNull(tag); - int type = NBTUtils.getTypeCode(tag.getClass()); + int type = tag.getTypeCode(); writeNamedTagName(name, type); if (type == NBTConstants.TYPE_END) { @@ -196,7 +198,7 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da } public void writeTag(Tag tag) throws IOException { - int type = NBTUtils.getTypeCode(tag.getClass()); + int type = tag.getTypeCode(); os.writeByte(type); writeTagPayload(tag); } @@ -212,7 +214,7 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da * @throws IOException if an I/O error occurs. */ public void writeTagPayload(Tag tag) throws IOException { - int type = NBTUtils.getTypeCode(tag.getClass()); + int type = tag.getTypeCode(); switch (type) { case NBTConstants.TYPE_END: writeEndTagPayload((EndTag) tag); @@ -287,7 +289,7 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da * @throws IOException if an I/O error occurs. */ private void writeCompoundTagPayload(CompoundTag tag) throws IOException { - for (Map.Entry entry : tag.getValue().entrySet()) { + for (Map.Entry> entry : tag.getValue().entrySet()) { writeNamedTag(entry.getKey(), entry.getValue()); } os.writeByte((byte) 0); // end tag - better way? @@ -300,7 +302,7 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da * @throws IOException if an I/O error occurs. */ private void writeListTagPayload(ListTag tag) throws IOException { - Class clazz = tag.getType(); + Class> clazz = tag.getType(); if (clazz == null) { clazz = CompoundTag.class; } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java index c899ba07b..b742cb6f8 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java @@ -20,7 +20,6 @@ package com.sk89q.jnbt; import com.sk89q.worldedit.math.Vector3; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; import com.sk89q.worldedit.world.storage.InvalidFormatException; import java.util.Map; @@ -33,6 +32,7 @@ import static com.google.common.base.Preconditions.checkNotNull; * * @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8. */ +@SuppressWarnings("ALL") @Deprecated public final class NBTUtils { @@ -48,7 +48,7 @@ public final class NBTUtils { * @param clazz the tag class * @return The type name. */ - public static String getTypeName(Class clazz) { + public static String getTypeName(Class> clazz) { if (clazz.equals(ByteArrayTag.class)) { return "TAG_Byte_Array"; } else if (clazz.equals(ByteTag.class)) { @@ -77,7 +77,7 @@ public final class NBTUtils { return "TAG_Long_Array"; } else { throw new IllegalArgumentException("Invalid tag class (" - + clazz.getName() + ")."); + + clazz.getName() + ")."); } } @@ -88,11 +88,35 @@ public final class NBTUtils { * @return The type code. * @throws IllegalArgumentException if the tag class is invalid. */ - public static int getTypeCode(Class clazz) { - if (LazyCompoundTag.class.isAssignableFrom(clazz)) { - return BinaryTagTypes.COMPOUND.id(); + public static int getTypeCode(Class> clazz) { + if (clazz == ByteArrayTag.class) { + return NBTConstants.TYPE_BYTE_ARRAY; + } else if (clazz == ByteTag.class) { + return NBTConstants.TYPE_BYTE; + } else if (clazz == CompoundTag.class) { + return NBTConstants.TYPE_COMPOUND; + } else if (clazz == DoubleTag.class) { + return NBTConstants.TYPE_DOUBLE; + } else if (clazz == EndTag.class) { + return NBTConstants.TYPE_END; + } else if (clazz == FloatTag.class) { + return NBTConstants.TYPE_FLOAT; + } else if (clazz == IntArrayTag.class) { + return NBTConstants.TYPE_INT_ARRAY; + } else if (clazz == IntTag.class) { + return NBTConstants.TYPE_INT; + } else if (clazz.equals(ListTag.class) /* I hate this, it wouldn't do == b/c generics */) { + return NBTConstants.TYPE_LIST; + } else if (clazz == LongArrayTag.class) { + return NBTConstants.TYPE_LONG_ARRAY; + } else if (clazz == LongTag.class) { + return NBTConstants.TYPE_LONG; + } else if (clazz == ShortTag.class) { + return NBTConstants.TYPE_SHORT; + } else if (clazz == StringTag.class) { + return NBTConstants.TYPE_STRING; } - return AdventureNBTConverter.getAdventureType(clazz).id(); + throw new IllegalArgumentException("Invalid tag class (" + clazz.getName() + ")"); } /** @@ -102,38 +126,8 @@ public final class NBTUtils { * @return The class. * @throws IllegalArgumentException if the tag type is invalid. */ - public static Class getTypeClass(int type) { - switch (type) { - case NBTConstants.TYPE_END: - return EndTag.class; - case NBTConstants.TYPE_BYTE: - return ByteTag.class; - case NBTConstants.TYPE_SHORT: - return ShortTag.class; - case NBTConstants.TYPE_INT: - return IntTag.class; - case NBTConstants.TYPE_LONG: - return LongTag.class; - case NBTConstants.TYPE_FLOAT: - return FloatTag.class; - case NBTConstants.TYPE_DOUBLE: - return DoubleTag.class; - case NBTConstants.TYPE_BYTE_ARRAY: - return ByteArrayTag.class; - case NBTConstants.TYPE_STRING: - return StringTag.class; - case NBTConstants.TYPE_LIST: - return ListTag.class; - case NBTConstants.TYPE_COMPOUND: - return CompoundTag.class; - case NBTConstants.TYPE_INT_ARRAY: - return IntArrayTag.class; - case NBTConstants.TYPE_LONG_ARRAY: - return LongArrayTag.class; - default: - throw new IllegalArgumentException("Invalid tag type : " + type - + "."); - } + public static Class> getTypeClass(int type) { + return NBTConstants.getClassFromType(type); } /** @@ -145,7 +139,7 @@ public final class NBTUtils { * @param listTag the list tag * @return a vector */ - public static Vector3 toVector(ListTag listTag) { + public static Vector3 toVector(ListTag listTag) { checkNotNull(listTag); return Vector3.at(listTag.asDouble(0), listTag.asDouble(1), listTag.asDouble(2)); } @@ -159,12 +153,12 @@ public final class NBTUtils { * @return child tag * @throws InvalidFormatException if the format of the items is invalid */ - public static T getChildTag(Map items, String key, Class expected) throws + public static > T getChildTag(Map> items, String key, Class expected) throws InvalidFormatException { if (!items.containsKey(key)) { throw new InvalidFormatException("Missing a \"" + key + "\" tag"); } - Tag tag = items.get(key); + Tag tag = items.get(key); if (!expected.isInstance(tag)) { throw new InvalidFormatException(key + " tag is not of tag type " + expected.getName()); } @@ -179,7 +173,7 @@ public final class NBTUtils { * @param uuid {@link UUID} to add * @since 2.4.0 */ - public static void addUUIDToMap(Map map, UUID uuid) { + public static void addUUIDToMap(Map> map, UUID uuid) { int[] uuidArray = new int[4]; uuidArray[0] = (int) (uuid.getMostSignificantBits() >> 32); uuidArray[1] = (int) uuid.getMostSignificantBits(); diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NamedTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NamedTag.java index c7e2f9f28..e83f135de 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NamedTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NamedTag.java @@ -30,7 +30,7 @@ import static com.google.common.base.Preconditions.checkNotNull; public class NamedTag { private final String name; - private final Tag tag; + private final Tag tag; /** * Create a new named tag. @@ -38,7 +38,7 @@ public class NamedTag { * @param name the name * @param tag the tag */ - public NamedTag(String name, Tag tag) { + public NamedTag(String name, Tag tag) { checkNotNull(name); checkNotNull(tag); this.name = name; @@ -59,7 +59,7 @@ public class NamedTag { * * @return the tag */ - public Tag getTag() { + public Tag getTag() { return tag; } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java index abbd06b3f..d0b9590fa 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java @@ -19,41 +19,32 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.ShortBinaryTag; +import com.fastasyncworldedit.core.jnbt.NumberTag; +import org.enginehub.linbus.tree.LinShortTag; /** * The {@code TAG_Short} tag. * - * @deprecated Use {@link ShortBinaryTag}. + * @deprecated Use {@link LinShortTag}. */ @Deprecated -public final class ShortTag extends Tag { - - private final ShortBinaryTag innerTag; - +public final class ShortTag extends NumberTag { /** * Creates the tag with an empty name. * * @param value the value of the tag */ public ShortTag(short value) { - super(); - this.innerTag = ShortBinaryTag.of(value); + super(LinShortTag.of(value)); } - public ShortTag(ShortBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public ShortBinaryTag asBinaryTag() { - return this.innerTag; + public ShortTag(LinShortTag tag) { + super(tag); } @Override public Short getValue() { - return innerTag.value(); + return linTag.value(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java index 483263752..2bc78f141 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java @@ -19,44 +19,33 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; +import org.enginehub.linbus.tree.LinStringTag; import static com.google.common.base.Preconditions.checkNotNull; /** * The {@code TAG_String} tag. * - * @deprecated Use {@link StringBinaryTag}. + * @deprecated Use {@link LinStringTag}. */ @Deprecated -public final class StringTag extends Tag { - - private final StringBinaryTag innerTag; - +public final class StringTag extends Tag { /** * Creates the tag with an empty name. * * @param value the value of the tag */ public StringTag(String value) { - super(); - checkNotNull(value); - this.innerTag = StringBinaryTag.of(value); + super(LinStringTag.of(checkNotNull(value))); } - public StringTag(StringBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public StringBinaryTag asBinaryTag() { - return this.innerTag; + public StringTag(LinStringTag tag) { + super(tag); } @Override public String getValue() { - return innerTag.value(); + return linTag.value(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java index 6327f4133..80df4c1cb 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java @@ -19,26 +19,43 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.BinaryTagLike; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.ToLinTag; + +import javax.annotation.Nonnull; /** * Represents a NBT tag. * - * @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8. + * @deprecated JNBT is being removed for lin-bus in WorldEdit 8, use {@link LinTag} instead */ -@Deprecated(forRemoval = true) -public abstract class Tag implements BinaryTagLike { +@Deprecated +public abstract class Tag> implements ToLinTag { + + protected final LT linTag; + + protected Tag(LT linTag) { + this.linTag = linTag; + } /** * Gets the value of this tag. * * @return the value */ - public abstract Object getValue(); + public V getValue() { + return linTag.value(); + } @Override public String toString() { - return asBinaryTag().toString(); + return toLinTag().toString(); + } + + @Override + @Nonnull + public LT toLinTag() { + return linTag; } //FAWE start 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 7642f3d60..be1740dc4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -76,7 +76,6 @@ import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Identifiable; import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -84,6 +83,8 @@ import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.snapshot.experimental.Snapshot; import com.zaxxer.sparsebits.SparseBitSet; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinTagType; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -1513,13 +1514,13 @@ public class LocalSession implements TextureHolder { BaseBlock block = ServerCUIHandler.createStructureBlock(player); if (block != null) { - CompoundBinaryTag tags = Objects.requireNonNull( - block.getNbt(), "createStructureBlock should return nbt" + LinCompoundTag tags = Objects.requireNonNull( + block.getNbt(), "createStructureBlock should return nbt" ); BlockVector3 tempCuiTemporaryBlock = BlockVector3.at( - tags.getInt("x"), - tags.getInt("y"), - tags.getInt("z") + tags.getTag("x", LinTagType.intTag()).valueAsInt(), + tags.getTag("y", LinTagType.intTag()).valueAsInt(), + tags.getTag("z", LinTagType.intTag()).valueAsInt() ); // If it's null, we don't need to do anything. The old was already removed. if (cuiTemporaryBlock != null && !tempCuiTemporaryBlock.equals(cuiTemporaryBlock)) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java index fe2e1a635..552dc6f56 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java @@ -20,15 +20,13 @@ package com.sk89q.worldedit.blocks; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.TagStringIO; import com.sk89q.worldedit.world.NbtValued; import com.sk89q.worldedit.world.item.ItemType; +import org.enginehub.linbus.format.snbt.LinStringIO; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; -import java.io.IOException; import static com.google.common.base.Preconditions.checkNotNull; @@ -42,9 +40,7 @@ public class BaseItem implements NbtValued { private ItemType itemType; @Nullable - //FAWE start - Use LR & CBT over CompoundTag - private LazyReference nbtData; - //FAWE end + private LazyReference nbtData; /** * Construct the object. @@ -56,6 +52,29 @@ public class BaseItem implements NbtValued { this.itemType = itemType; } + /** + * Construct the object. + * + * @param itemType Type of the item + * @param nbtData NBT Compound tag + */ + @Deprecated + public BaseItem(ItemType itemType, @Nullable CompoundTag nbtData) { + this(itemType, nbtData == null ? null : LazyReference.from(nbtData::toLinTag)); + } + + /** + * Construct the object. + * + * @param itemType Type of the item + * @param tag NBT Compound tag + */ + public BaseItem(ItemType itemType, @Nullable LazyReference tag) { + checkNotNull(itemType); + this.itemType = itemType; + this.nbtData = tag; + } + /** * Get the type of item. * @@ -77,29 +96,6 @@ public class BaseItem implements NbtValued { //FAWE start - /** - * Construct the object. - * - * @param itemType Type of the item - * @param nbtData NBT Compound tag - */ - @Deprecated - public BaseItem(ItemType itemType, @Nullable CompoundTag nbtData) { - this(itemType, nbtData == null ? null : LazyReference.from(nbtData::asBinaryTag)); - } - - /** - * Construct the object. - * - * @param itemType Type of the item - * @param tag NBT Compound tag - */ - public BaseItem(ItemType itemType, @Nullable LazyReference tag) { - checkNotNull(itemType); - this.itemType = itemType; - this.nbtData = tag; - } - @Deprecated @Nullable public Object getNativeItem() { @@ -108,25 +104,20 @@ public class BaseItem implements NbtValued { @Nullable @Override - public LazyReference getNbtReference() { + public LazyReference getNbtReference() { return this.nbtData; } @Override - public void setNbtReference(@Nullable LazyReference nbtData) { + public void setNbtReference(@Nullable LazyReference nbtData) { this.nbtData = nbtData; } @Override public String toString() { String nbtString = ""; - LazyReference nbtData = this.nbtData; if (nbtData != null) { - try { - nbtString = TagStringIO.get().asString(nbtData.getValue()); - } catch (IOException e) { - WorldEdit.logger.error("Failed to serialize NBT of Item", e); - } + nbtString = LinStringIO.writeToString(nbtData.getValue()); } return getType().id() + nbtString; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItemStack.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItemStack.java index 07a9aa147..b83efe24a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItemStack.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItemStack.java @@ -24,8 +24,8 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.item.ItemType; +import org.enginehub.linbus.tree.LinCompoundTag; /** * Represents a stack of BaseItems. @@ -70,6 +70,18 @@ public class BaseItemStack extends BaseItem { this.amount = amount; } + /** + * Construct the object. + * + * @param id The item type + * @param tag Tag value + * @param amount amount in the stack + */ + public BaseItemStack(ItemType id, LazyReference tag, int amount) { + super(id, tag); + this.amount = amount; + } + /** * Get the number of items in the stack. * @@ -93,18 +105,4 @@ public class BaseItemStack extends BaseItem { .getRegistries().getItemRegistry().getRichName(this); } - //FAWE start - - /** - * Construct the object. - * - * @param id The item type - * @param tag Tag value - * @param amount amount in the stack - */ - public BaseItemStack(ItemType id, LazyReference tag, int amount) { - super(id, tag); - this.amount = amount; - } - //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java index 235cdf761..b369ddd87 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java @@ -21,10 +21,10 @@ package com.sk89q.worldedit.entity; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.NbtValued; import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.entity.EntityTypes; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; @@ -47,7 +47,7 @@ public class BaseEntity implements NbtValued { private final EntityType type; @Nullable - private LazyReference nbtData; + private LazyReference nbtData; /** * Create a new base entity. @@ -69,7 +69,7 @@ public class BaseEntity implements NbtValued { * @param type the entity type * @param nbtData NBT data */ - public BaseEntity(EntityType type, LazyReference nbtData) { + public BaseEntity(EntityType type, LazyReference nbtData) { this(type); setNbtReference(nbtData); } @@ -97,12 +97,12 @@ public class BaseEntity implements NbtValued { @Nullable @Override - public LazyReference getNbtReference() { + public LazyReference getNbtReference() { return nbtData; } @Override - public void setNbtReference(@Nullable LazyReference nbtData) { + public void setNbtReference(@Nullable LazyReference nbtData) { this.nbtData = nbtData; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java index b889d4dca..2eb4fbfe3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java @@ -20,7 +20,6 @@ package com.sk89q.worldedit.extension.factory.parser; import com.fastasyncworldedit.core.configuration.Caption; -import com.fastasyncworldedit.core.util.NbtUtils; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; @@ -35,13 +34,13 @@ import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.TagStringIO; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; +import org.enginehub.linbus.format.snbt.LinStringIO; +import org.enginehub.linbus.stream.exception.NbtParseException; +import org.enginehub.linbus.tree.LinCompoundTag; -import java.io.IOException; import java.util.Locale; import java.util.stream.Stream; @@ -59,7 +58,7 @@ public class DefaultItemParser extends InputParser { @Override public BaseItem parseFromInput(String input, ParserContext context) throws InputParseException { ItemType itemType; - CompoundBinaryTag itemNbtData = null; + LinCompoundTag itemNbtData = null; BaseItem item = null; @@ -128,20 +127,21 @@ public class DefaultItemParser extends InputParser { } if (nbtString != null) { + LinCompoundTag otherTag; try { - CompoundBinaryTag otherTag = TagStringIO.get().asCompound(nbtString); - if (itemNbtData == null) { - itemNbtData = otherTag; - } else { - itemNbtData.put(NbtUtils.getCompoundBinaryTagValues(otherTag)); - } - } catch (IOException e) { + otherTag = LinStringIO.readFromStringUsing(nbtString, LinCompoundTag::readFrom); + } catch (NbtParseException e) { throw new NoMatchException(TranslatableComponent.of( "worldedit.error.invalid-nbt", TextComponent.of(input), TextComponent.of(e.getMessage()) )); } + if (itemNbtData == null) { + itemNbtData = otherTag; + } else { + itemNbtData = itemNbtData.toBuilder().putAll(otherTag.value()).build(); + } } item = new BaseItem(itemType, itemNbtData == null ? null : LazyReference.computed(itemNbtData)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index b861dbd6b..cf4623739 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -186,7 +186,7 @@ public class BlockArrayClipboard implements Clipboard { } @Override - public > boolean setBlock(BlockVector3 position, B block) throws WorldEditException { + public > boolean setBlock(BlockVector3 position, B block) { if (region.contains(position)) { //FAWE - get points final int x = position.x(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java index 5aafa220e..1fd9dda9a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java @@ -153,7 +153,7 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); // Check - Map schematic = schematicTag.getValue(); + Map> schematic = schematicTag.getValue(); if (!schematic.containsKey("Version")) { return false; } 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 aebef3e9a..945cd6981 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 @@ -20,17 +20,7 @@ package com.sk89q.worldedit.extent.clipboard.io; import com.google.common.collect.ImmutableList; -import com.sk89q.jnbt.AdventureNBTConverter; -import com.sk89q.jnbt.ByteArrayTag; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.IntTag; -import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.NBTInputStream; -import com.sk89q.jnbt.NamedTag; -import com.sk89q.jnbt.ShortTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; @@ -49,7 +39,7 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.collection.BlockMap; -import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.entity.EntityType; @@ -57,27 +47,25 @@ import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; import com.sk89q.worldedit.world.storage.NBTConversions; import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinRootEntry; +import org.enginehub.linbus.tree.LinTagType; import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; +import java.io.UncheckedIOException; import java.util.HashSet; import java.util.List; import java.util.Locale; -import java.util.Map; -import java.util.Optional; import java.util.Set; -import static com.google.common.base.Preconditions.checkNotNull; - /** * Reads schematic files that are compatible with MCEdit and other editors. */ public class MCEditSchematicReader extends NBTSchematicReader { private static final Logger LOGGER = LogManagerCompat.getLogger(); - private final NBTInputStream inputStream; - private final DataFixer fixer; + private final LinRootEntry root; private static final ImmutableList COMPATIBILITY_HANDLERS = ImmutableList.of( new SignCompatibilityHandler(), @@ -98,30 +86,30 @@ public class MCEditSchematicReader extends NBTSchematicReader { * @param inputStream the input stream to read from */ public MCEditSchematicReader(NBTInputStream inputStream) { - checkNotNull(inputStream); - this.inputStream = inputStream; - this.fixer = null; - //com.sk89q.worldedit.WorldEdit.getInstance().getPlatformManager().queryCapability( - //com.sk89q.worldedit.extension.platform.Capability.WORLD_EDITING).getDataFixer(); + try { + var tag = inputStream.readNamedTag(); + this.root = new LinRootEntry(tag.getName(), (LinCompoundTag) tag.getTag().toLinTag()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + MCEditSchematicReader(LinRootEntry root) { + this.root = root; } @Override public Clipboard read() throws IOException { // Schematic tag - NamedTag rootTag = inputStream.readNamedTag(); - if (!rootTag.getName().equals("Schematic")) { + if (!root.name().equals("Schematic")) { throw new IOException("Tag 'Schematic' does not exist or is not first"); } - CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); + var schematicTag = root.value(); - // Check - Map schematic = schematicTag.getValue(); - if (!schematic.containsKey("Blocks")) { + if (!schematicTag.value().containsKey("Blocks")) { throw new IOException("Schematic file is missing a 'Blocks' tag"); } - - // Check type of Schematic - String materials = requireTag(schematic, "Materials", StringTag.class).getValue(); + String materials = schematicTag.getTag("Materials", LinTagType.stringTag()).value(); if (!materials.equals("Alpha")) { throw new IOException("Schematic file is not an Alpha schematic"); } @@ -134,42 +122,38 @@ public class MCEditSchematicReader extends NBTSchematicReader { Region region; // Get information - short width = requireTag(schematic, "Width", ShortTag.class).getValue(); - short height = requireTag(schematic, "Height", ShortTag.class).getValue(); - short length = requireTag(schematic, "Length", ShortTag.class).getValue(); + short width = schematicTag.getTag("Width", LinTagType.shortTag()).valueAsShort(); + short height = schematicTag.getTag("Height", LinTagType.shortTag()).valueAsShort(); + short length = schematicTag.getTag("Length", LinTagType.shortTag()).valueAsShort(); - try { - int originX = requireTag(schematic, "WEOriginX", IntTag.class).getValue(); - int originY = requireTag(schematic, "WEOriginY", IntTag.class).getValue(); - int originZ = requireTag(schematic, "WEOriginZ", IntTag.class).getValue(); - BlockVector3 min = BlockVector3.at(originX, originY, originZ); + int originX = schematicTag.getTag("WEOriginX", LinTagType.intTag()).valueAsInt(); + int originY = schematicTag.getTag("WEOriginY", LinTagType.intTag()).valueAsInt(); + int originZ = schematicTag.getTag("WEOriginZ", LinTagType.intTag()).valueAsInt(); + BlockVector3 min = BlockVector3.at(originX, originY, originZ); - int offsetX = requireTag(schematic, "WEOffsetX", IntTag.class).getValue(); - int offsetY = requireTag(schematic, "WEOffsetY", IntTag.class).getValue(); - int offsetZ = requireTag(schematic, "WEOffsetZ", IntTag.class).getValue(); - BlockVector3 offset = BlockVector3.at(offsetX, offsetY, offsetZ); + int offsetX = schematicTag.getTag("WEOffsetX", LinTagType.intTag()).valueAsInt(); + int offsetY = schematicTag.getTag("WEOffsetY", LinTagType.intTag()).valueAsInt(); + int offsetZ = schematicTag.getTag("WEOffsetZ", LinTagType.intTag()).valueAsInt(); + BlockVector3 offset = BlockVector3.at(offsetX, offsetY, offsetZ); - origin = min.subtract(offset); - region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE)); - } catch (IOException ignored) { - origin = BlockVector3.ZERO; - region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE)); - } + origin = min.subtract(offset); + region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE)); // ==================================================================== // Blocks // ==================================================================== // Get blocks - byte[] blockId = requireTag(schematic, "Blocks", ByteArrayTag.class).getValue(); - byte[] blockData = requireTag(schematic, "Data", ByteArrayTag.class).getValue(); + byte[] blockId = schematicTag.getTag("Blocks", LinTagType.byteArrayTag()).value(); + byte[] blockData = schematicTag.getTag("Data", LinTagType.byteArrayTag()).value(); byte[] addId = new byte[0]; short[] blocks = new short[blockId.length]; // Have to later combine IDs // We support 4096 block IDs using the same method as vanilla Minecraft, where // the highest 4 bits are stored in a separate byte array. - if (schematic.containsKey("AddBlocks")) { - addId = requireTag(schematic, "AddBlocks", ByteArrayTag.class).getValue(); + LinByteArrayTag addBlocks = schematicTag.findTag("AddBlocks", LinTagType.byteArrayTag()); + if (addBlocks != null) { + addId = addBlocks.value(); } // Combine the AddBlocks data with the first 8-bit block ID @@ -186,21 +170,17 @@ public class MCEditSchematicReader extends NBTSchematicReader { } // Need to pull out tile entities - final ListTag tileEntityTag = getTag(schematic, "TileEntities", ListTag.class); - List tileEntities = tileEntityTag == null ? new ArrayList<>() : tileEntityTag.getValue(); + var tileEntityTag = schematicTag.findListTag("TileEntities", LinTagType.compoundTag()); + List tileEntities = tileEntityTag == null ? List.of() : tileEntityTag.value(); BlockMap tileEntityBlocks = BlockMap.createForBaseBlock(); - for (Tag tag : tileEntities) { - if (!(tag instanceof CompoundTag)) { - continue; - } - CompoundTag t = (CompoundTag) tag; - Map values = new HashMap<>(t.getValue()); - String id = t.getString("id"); - values.put("id", new StringTag(convertBlockEntityId(id))); - int x = t.getInt("x"); - int y = t.getInt("y"); - int z = t.getInt("z"); + for (LinCompoundTag tag : tileEntities) { + var newTag = tag.toBuilder(); + String id = tag.getTag("id", LinTagType.stringTag()).value(); + newTag.putString("id", convertBlockEntityId(id)); + int x = tag.getTag("x", LinTagType.intTag()).valueAsInt(); + int y = tag.getTag("y", LinTagType.intTag()).valueAsInt(); + int z = tag.getTag("z", LinTagType.intTag()).valueAsInt(); int index = y * width * length + z * width + x; //FAWE start - tile entity safety - perhaps caused by the old issue with tile entities created in the wrong @@ -211,44 +191,17 @@ public class MCEditSchematicReader extends NBTSchematicReader { } BlockState block = getBlockState(blocks[index], blockData[index]); - BlockState newBlock = block; - if (newBlock != null) { - for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) { - if (handler.isAffectedBlock(newBlock)) { - newBlock = handler.updateNBT(block, values).toImmutableState(); - if (newBlock == null || values.isEmpty()) { - break; - } - } + if (block == null) { + continue; + } + var updatedBlock = block.toBaseBlock(LazyReference.from(newTag::build)); + for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) { + updatedBlock = handler.updateNbt(updatedBlock); + if (updatedBlock.getNbtReference() == null) { + break; } } - if (values.isEmpty()) { - t = null; - } else { - t = new CompoundTag(values); - } - - if (fixer != null && t != null) { - //FAWE start - BinaryTag - t = (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp( - DataFixer.FixTypes.BLOCK_ENTITY, - t.asBinaryTag(), - -1 - )); - //FAWE end - } - - BlockVector3 vec = BlockVector3.at(x, y, z); - // Insert into the map if we have changed the block or have a tag - BlockState blockToInsert = newBlock != null - ? newBlock - : (t != null ? block : null); - if (blockToInsert != null) { - BaseBlock baseBlock = t != null - ? blockToInsert.toBaseBlock(new CompoundTag(t.getValue())) - : blockToInsert.toBaseBlock(); - tileEntityBlocks.put(vec, baseBlock); - } + tileEntityBlocks.put(BlockVector3.at(x, y, z), updatedBlock); } BlockArrayClipboard clipboard = new BlockArrayClipboard(region); @@ -261,16 +214,10 @@ public class MCEditSchematicReader extends NBTSchematicReader { for (int z = 0; z < length; ++z) { int index = y * width * length + z * width + x; BlockVector3 pt = BlockVector3.at(x, y, z); - BaseBlock state = Optional.ofNullable(tileEntityBlocks.get(pt)) - .orElseGet(() -> { - BlockState blockState = getBlockState(blocks[index], blockData[index]); - return blockState == null ? null : blockState.toBaseBlock(); - }); - - try { - if (state != null) { - clipboard.setBlock(region.getMinimumPoint().add(pt), state); - } else { + BaseBlock state = tileEntityBlocks.get(pt); + if (state == null) { + BlockState blockState = getBlockState(blocks[index], blockData[index]); + if (blockState == null) { short block = blocks[index]; byte data = blockData[index]; int combined = block << 8 | data; @@ -278,9 +225,12 @@ public class MCEditSchematicReader extends NBTSchematicReader { LOGGER.warn("Unknown block when loading schematic: {} {}. This is most likely a" + "bad schematic.", block, data); } + continue; } - } catch (WorldEditException ignored) { // BlockArrayClipboard won't throw this + state = blockState.toBaseBlock(); } + + clipboard.setBlock(region.getMinimumPoint().add(pt), state); } } } @@ -289,40 +239,25 @@ public class MCEditSchematicReader extends NBTSchematicReader { // Entities // ==================================================================== - ListTag entityList = getTag(schematic, "Entities", ListTag.class); + var entityList = schematicTag.findListTag("Entities", LinTagType.compoundTag()); if (entityList != null) { - List entityTags = entityList.getValue(); - for (Tag tag : entityTags) { - if (tag instanceof CompoundTag) { - CompoundTag compound = (CompoundTag) tag; - if (fixer != null) { - //FAWE start - BinaryTag - compound = (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp( - DataFixer.FixTypes.ENTITY, - compound.asBinaryTag(), - -1 - )); - //FAWE end - } - String id = convertEntityId(compound.getString("id")); - Location location = NBTConversions.toLocation( - clipboard, - compound.getListTag("Pos"), - compound.getListTag("Rotation") - ); - if (!id.isEmpty()) { - EntityType entityType = EntityTypes.get(id.toLowerCase(Locale.ROOT)); - if (entityType != null) { - for (EntityNBTCompatibilityHandler compatibilityHandler : ENTITY_COMPATIBILITY_HANDLERS) { - if (compatibilityHandler.isAffectedEntity(entityType, compound)) { - compound = compatibilityHandler.updateNBT(entityType, compound); - } - } - BaseEntity state = new BaseEntity(entityType, compound); - clipboard.createEntity(location, state); - } else { - LOGGER.warn("Unknown entity when pasting schematic: " + id.toLowerCase(Locale.ROOT)); + for (LinCompoundTag tag : entityList.value()) { + String id = convertEntityId(tag.getTag("id", LinTagType.stringTag()).value()); + Location location = NBTConversions.toLocation( + clipboard, + tag.getListTag("Pos", LinTagType.doubleTag()), + tag.getListTag("Rotation", LinTagType.floatTag()) + ); + if (!id.isEmpty()) { + EntityType entityType = EntityTypes.get(id.toLowerCase(Locale.ROOT)); + if (entityType != null) { + for (EntityNBTCompatibilityHandler compatibilityHandler : ENTITY_COMPATIBILITY_HANDLERS) { + tag = compatibilityHandler.updateNbt(entityType, tag); } + BaseEntity state = new BaseEntity(entityType, LazyReference.computed(tag)); + clipboard.createEntity(location, state); + } else { + LOGGER.warn("Unknown entity when pasting schematic: " + id.toLowerCase(Locale.ROOT)); } } } @@ -494,7 +429,6 @@ public class MCEditSchematicReader extends NBTSchematicReader { @Override public void close() throws IOException { - inputStream.close(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java index 0328b1c76..a6b9c1400 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java @@ -30,13 +30,13 @@ import java.util.Map; */ public abstract class NBTSchematicReader implements ClipboardReader { - protected static T requireTag(Map items, String key, Class expected) throws IOException { + protected static > T requireTag(Map> items, String key, Class expected) throws IOException { if (!items.containsKey(key)) { throw new IOException("Schematic file is missing a \"" + key + "\" tag of type " + expected.getName()); } - Tag tag = items.get(key); + Tag tag = items.get(key); if (!expected.isInstance(tag)) { throw new IOException(key + " tag is not of tag type " + expected.getName() + ", got " + tag.getClass().getName() + " instead"); @@ -46,12 +46,12 @@ public abstract class NBTSchematicReader implements ClipboardReader { } @Nullable - protected static T getTag(Map items, String key, Class expected) { + protected static > T getTag(Map> items, String key, Class expected) { if (!items.containsKey(key)) { return null; } - Tag test = items.get(key); + Tag test = items.get(key); if (!expected.isInstance(test)) { return null; } 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 a140b666a..ec82be228 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 @@ -21,7 +21,7 @@ package com.sk89q.worldedit.extent.clipboard.io; import com.fastasyncworldedit.core.configuration.Caption; import com.google.common.collect.Maps; -import com.sk89q.jnbt.AdventureNBTConverter; +import com.sk89q.jnbt.LinBusConverter; import com.sk89q.jnbt.ByteArrayTag; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntArrayTag; @@ -64,7 +64,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.OptionalInt; -import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; @@ -97,7 +96,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { @Override public Clipboard read() throws IOException { CompoundTag schematicTag = getBaseTag(); - Map schematic = schematicTag.getValue(); + Map> schematic = schematicTag.getValue(); final Platform platform = WorldEdit.getInstance().getPlatformManager() .queryCapability(Capability.WORLD_EDITING); @@ -147,7 +146,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { public OptionalInt getDataVersion() { try { CompoundTag schematicTag = getBaseTag(); - Map schematic = schematicTag.getValue(); + Map> schematic = schematicTag.getValue(); if (schematicVersion == 1) { return OptionalInt.of(Constants.DATA_VERSION_MC_1_13_2); } else if (schematicVersion == 2) { @@ -168,7 +167,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); // Check - Map schematic = schematicTag.getValue(); + Map> schematic = schematicTag.getValue(); // Be lenient about the specific nesting level of the Schematic tag // Also allows checking the version from newer versions of the specification @@ -184,7 +183,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { private BlockArrayClipboard readVersion1(CompoundTag schematicTag) throws IOException { BlockVector3 origin; Region region; - Map schematic = schematicTag.getValue(); + Map> schematic = schematicTag.getValue(); int width = requireTag(schematic, "Width", ShortTag.class).getValue(); int height = requireTag(schematic, "Height", ShortTag.class).getValue(); @@ -206,7 +205,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { CompoundTag metadataTag = getTag(schematic, "Metadata", CompoundTag.class); if (metadataTag != null && metadataTag.containsKey("WEOffsetX")) { // We appear to have WorldEdit Metadata - Map metadata = metadataTag.getValue(); + Map> metadata = metadataTag.getValue(); int offsetX = requireTag(metadata, "WEOffsetX", IntTag.class).getValue(); int offsetY = requireTag(metadata, "WEOffsetY", IntTag.class).getValue(); int offsetZ = requireTag(metadata, "WEOffsetZ", IntTag.class).getValue(); @@ -219,7 +218,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { } IntTag paletteMaxTag = getTag(schematic, "PaletteMax", IntTag.class); - Map paletteObject = requireTag(schematic, "Palette", CompoundTag.class).getValue(); + Map> paletteObject = requireTag(schematic, "Palette", CompoundTag.class).getValue(); if (paletteMaxTag != null && paletteObject.size() != paletteMaxTag.getValue()) { throw new IOException("Block palette size does not match expected size."); } @@ -248,21 +247,17 @@ public class SpongeSchematicReader extends NBTSchematicReader { byte[] blocks = requireTag(schematic, "BlockData", ByteArrayTag.class).getValue(); - Map> tileEntitiesMap = new HashMap<>(); + Map>> tileEntitiesMap = new HashMap<>(); ListTag tileEntities = getTag(schematic, "BlockEntities", ListTag.class); if (tileEntities == null) { tileEntities = getTag(schematic, "TileEntities", ListTag.class); } if (tileEntities != null) { - List> tileEntityTags = tileEntities.getValue().stream() - .map(tag -> (CompoundTag) tag) - .map(CompoundTag::getValue) - .collect(Collectors.toList()); - - for (Map tileEntity : tileEntityTags) { + for (Object tileTag : tileEntities.getValue()) { + Map> tileEntity = ((CompoundTag) tileTag).getValue(); int[] pos = requireTag(tileEntity, "Pos", IntArrayTag.class).getValue(); final BlockVector3 pt = BlockVector3.at(pos[0], pos[1], pos[2]); - Map values = Maps.newHashMap(tileEntity); + Map> values = Maps.newHashMap(tileEntity); values.put("x", new IntTag(pt.x())); values.put("y", new IntTag(pt.y())); values.put("z", new IntTag(pt.z())); @@ -279,10 +274,10 @@ public class SpongeSchematicReader extends NBTSchematicReader { values.remove("Id"); values.remove("Pos"); if (fixer != null) { - //FAWE start - BinaryTag - tileEntity = ((CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp( + //FAWE start - LinTag + tileEntity = ((CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp( DataFixer.FixTypes.BLOCK_ENTITY, - new CompoundTag(values).asBinaryTag(), + new CompoundTag(values).toLinTag(), dataVersion ))).getValue(); //FAWE end @@ -341,7 +336,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { } private Clipboard readVersion2(BlockArrayClipboard version1, CompoundTag schematicTag) throws IOException { - Map schematic = schematicTag.getValue(); + Map> schematic = schematicTag.getValue(); if (schematic.containsKey("BiomeData")) { readBiomes(version1, schematic); } @@ -351,7 +346,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { return version1; } - private void readBiomes(BlockArrayClipboard clipboard, Map schematic) throws IOException { + 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); @@ -361,7 +356,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { throw new IOException("Biome palette size does not match expected size."); } - for (Entry palettePart : paletteTag.getValue().entrySet()) { + for (Entry> palettePart : paletteTag.getValue().entrySet()) { String key = palettePart.getKey(); if (fixer != null) { key = fixer.fixUp(DataFixer.FixTypes.BIOME, key, dataVersion); @@ -411,7 +406,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { } } - private void readEntities(BlockArrayClipboard clipboard, Map schematic) throws IOException { + private void readEntities(BlockArrayClipboard clipboard, Map> schematic) throws IOException { List entList = requireTag(schematic, "Entities", ListTag.class).getValue(); if (entList.isEmpty()) { return; @@ -421,15 +416,15 @@ public class SpongeSchematicReader extends NBTSchematicReader { continue; } CompoundTag entityTag = (CompoundTag) et; - Map tags = entityTag.getValue(); + Map> tags = entityTag.getValue(); String id = requireTag(tags, "Id", StringTag.class).getValue(); entityTag = entityTag.createBuilder().putString("id", id).remove("Id").build(); if (fixer != null) { - //FAWE start - BinaryTag - entityTag = (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp( + //FAWE start - LinTag + entityTag = (CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp( DataFixer.FixTypes.ENTITY, - entityTag.asBinaryTag(), + entityTag.toLinTag(), dataVersion )); //FAWE end 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 dc313b259..38c0115e5 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 @@ -92,7 +92,7 @@ public class SpongeSchematicWriter implements ClipboardWriter { * @param clipboard The clipboard * @return The schematic map */ - private Map write2(Clipboard clipboard) { + private Map> write2(Clipboard clipboard) { Region region = clipboard.getRegion(); BlockVector3 origin = clipboard.getOrigin(); BlockVector3 min = region.getMinimumPoint(); @@ -111,12 +111,12 @@ public class SpongeSchematicWriter implements ClipboardWriter { throw new IllegalArgumentException("Length of region too large for a .schematic"); } - Map schematic = new HashMap<>(); + Map> schematic = new HashMap<>(); schematic.put("Version", new IntTag(CURRENT_VERSION)); schematic.put("DataVersion", new IntTag( WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion())); - Map metadata = new HashMap<>(); + Map> metadata = new HashMap<>(); metadata.put("WEOffsetX", new IntTag(offset.x())); metadata.put("WEOffsetY", new IntTag(offset.y())); metadata.put("WEOffsetZ", new IntTag(offset.z())); @@ -151,7 +151,7 @@ public class SpongeSchematicWriter implements ClipboardWriter { BlockVector3 point = BlockVector3.at(x0, y0, z0); BaseBlock block = clipboard.getFullBlock(point); if (block.getNbtData() != null) { - Map values = new HashMap<>(block.getNbtData().getValue()); + Map> values = new HashMap<>(block.getNbtData().getValue()); values.remove("id"); // Remove 'id' if it exists. We want 'Id' @@ -187,7 +187,7 @@ public class SpongeSchematicWriter implements ClipboardWriter { schematic.put("PaletteMax", new IntTag(paletteMax)); - Map paletteTag = new HashMap<>(); + Map> paletteTag = new HashMap<>(); palette.forEach((key, value) -> paletteTag.put(key, new IntTag(value))); schematic.put("Palette", new CompoundTag(paletteTag)); @@ -206,7 +206,7 @@ public class SpongeSchematicWriter implements ClipboardWriter { return schematic; } - private void writeBiomes(Clipboard clipboard, Map schematic) { + private void writeBiomes(Clipboard clipboard, Map> schematic) { BlockVector3 min = clipboard.getMinimumPoint(); int width = clipboard.getRegion().getWidth(); int length = clipboard.getRegion().getLength(); @@ -243,20 +243,20 @@ public class SpongeSchematicWriter implements ClipboardWriter { schematic.put("BiomePaletteMax", new IntTag(paletteMax)); - Map paletteTag = new HashMap<>(); + 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) { + 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(); + Map> values = Maps.newHashMap(); CompoundTag rawData = state.getNbtData(); if (rawData != null) { values.putAll(rawData.getValue()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BannerBlockCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BannerBlockCompatibilityHandler.java index 826967400..d4b7347f2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BannerBlockCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BannerBlockCompatibilityHandler.java @@ -19,21 +19,16 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.CompoundTagBuilder; -import com.sk89q.jnbt.IntTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTagType; public class BannerBlockCompatibilityHandler implements NBTCompatibilityHandler { @@ -55,17 +50,19 @@ public class BannerBlockCompatibilityHandler implements NBTCompatibilityHandler } @Override - public > boolean isAffectedBlock(B block) { - return block.getBlockType() == BlockTypes.WHITE_BANNER - || block.getBlockType() == BlockTypes.WHITE_WALL_BANNER; - } - - @Override - public > BlockStateHolder updateNBT(B block, Map values) { - Tag typeTag = values.get("Base"); - if (typeTag instanceof IntTag) { + public BaseBlock updateNbt(BaseBlock block) { + var blockType = block.getBlockType(); + if (blockType != BlockTypes.WHITE_BANNER && blockType != BlockTypes.WHITE_WALL_BANNER) { + return block; + } + var nbt = block.getNbt(); + if (nbt == null) { + return block; + } + LinIntTag typeTag = nbt.findTag("Base", LinTagType.intTag()); + if (typeTag != null) { boolean isWall = block.getBlockType() == BlockTypes.WHITE_WALL_BANNER; - String bannerType = convertBannerType(((IntTag) typeTag).getValue(), isWall); + String bannerType = convertBannerType(typeTag.valueAsInt(), isWall); if (bannerType != null) { BlockType type = BlockTypes.get("minecraft:" + bannerType); if (type != null) { @@ -79,29 +76,25 @@ public class BannerBlockCompatibilityHandler implements NBTCompatibilityHandler state = state.with(rotationProp, block.getState(RotationProperty)); } - values.remove("Base"); + var nbtBuilder = nbt.toBuilder(); + nbtBuilder.remove("Base"); - Tag patternsTag = values.get("Patterns"); - if (patternsTag instanceof ListTag) { - List tempList = new ArrayList<>(); - for (Tag pattern : ((ListTag) patternsTag).getValue()) { - if (pattern instanceof CompoundTag) { - Map patternMap = ((CompoundTag) pattern).getValue(); - Tag colorTag = patternMap.get("Color"); - - CompoundTagBuilder builder = CompoundTagBuilder.create(); - builder.putAll(patternMap); - if (colorTag instanceof IntTag) { - builder.putInt("Color", 15 - ((IntTag) colorTag).getValue()); - } - tempList.add(builder.build()); + var patternsTag = nbt.findListTag("Patterns", LinTagType.compoundTag()); + if (patternsTag != null) { + var newPatterns = LinListTag.builder(LinTagType.compoundTag()); + for (LinCompoundTag pattern : patternsTag.value()) { + LinIntTag color = pattern.findTag("Color", LinTagType.intTag()); + if (color != null) { + newPatterns.add(pattern.toBuilder() + .putInt("Color", 15 - color.valueAsInt()) + .build()); } else { - tempList.add(pattern); + newPatterns.add(pattern); } } - values.put("Patterns", new ListTag(((ListTag) patternsTag).getType(), tempList)); + nbtBuilder.put("Patterns", newPatterns.build()); } - return state; + return state.toBaseBlock(nbtBuilder.build()); } } } @@ -109,58 +102,27 @@ public class BannerBlockCompatibilityHandler implements NBTCompatibilityHandler } private static String convertBannerType(int oldType, boolean isWall) { - String color; - switch (oldType) { - case 0: - color = "black"; - break; - case 1: - color = "red"; - break; - case 2: - color = "green"; - break; - case 3: - color = "brown"; - break; - case 4: - color = "blue"; - break; - case 5: - color = "purple"; - break; - case 6: - color = "cyan"; - break; - case 7: - color = "light_gray"; - break; - case 8: - color = "gray"; - break; - case 9: - color = "pink"; - break; - case 10: - color = "lime"; - break; - case 11: - color = "yellow"; - break; - case 12: - color = "light_blue"; - break; - case 13: - color = "magenta"; - break; - case 14: - color = "orange"; - break; - case 15: - color = "white"; - break; - default: - return null; + String color = switch (oldType) { + case 0 -> "black"; + case 1 -> "red"; + case 2 -> "green"; + case 3 -> "brown"; + case 4 -> "blue"; + case 5 -> "purple"; + case 6 -> "cyan"; + case 7 -> "light_gray"; + case 8 -> "gray"; + case 9 -> "pink"; + case 10 -> "lime"; + case 11 -> "yellow"; + case 12 -> "light_blue"; + case 13 -> "magenta"; + case 14 -> "orange"; + case 15 -> "white"; + default -> null; + }; + if (color == null) { + return null; } return color + (isWall ? "_wall_banner" : "_banner"); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BedBlockCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BedBlockCompatibilityHandler.java index eea18f8df..c8c26cc91 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BedBlockCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BedBlockCompatibilityHandler.java @@ -19,18 +19,15 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; -import com.sk89q.jnbt.IntTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; +import org.enginehub.linbus.tree.LinTagType; -import java.util.Map; - -@SuppressWarnings("") public class BedBlockCompatibilityHandler implements NBTCompatibilityHandler { private static final Property FACING_PROPERTY; @@ -51,92 +48,63 @@ public class BedBlockCompatibilityHandler implements NBTCompatibilityHandler { } @Override - public > boolean isAffectedBlock(B block) { - return block.getBlockType() == BlockTypes.RED_BED; - } - - @Override - public > BlockStateHolder updateNBT(B block, Map values) { - Tag typeTag = values.get("color"); - if (typeTag instanceof IntTag) { - String bedType = convertBedType(((IntTag) typeTag).getValue()); - if (bedType != null) { - BlockType type = BlockTypes.get("minecraft:" + bedType); - if (type != null) { - BlockState state = type.getDefaultState(); - - Property facingProp = type.getProperty("facing"); - state = state.with(facingProp, block.getState(FACING_PROPERTY)); - - Property occupiedProp = type.getProperty("occupied"); - state = state.with(occupiedProp, false); - - Property partProp = type.getProperty("part"); - state = state.with(partProp, block.getState(PART_PROPERTY)); - - values.remove("color"); - return state; - } - } + public BaseBlock updateNbt(BaseBlock block) { + if (block.getBlockType() != BlockTypes.RED_BED) { + return block; } - return block; + var tag = block.getNbt(); + if (tag == null) { + return block; + } + var typeTag = tag.findTag("color", LinTagType.intTag()); + if (typeTag == null) { + return block; + } + String bedType = convertBedType(typeTag.valueAsInt()); + if (bedType == null) { + return block; + } + BlockType type = BlockTypes.get("minecraft:" + bedType); + if (type == null) { + return block; + } + BlockState state = type.getDefaultState(); + + Property facingProp = type.getProperty("facing"); + state = state.with(facingProp, block.getState(FACING_PROPERTY)); + + Property occupiedProp = type.getProperty("occupied"); + state = state.with(occupiedProp, false); + + Property partProp = type.getProperty("part"); + state = state.with(partProp, block.getState(PART_PROPERTY)); + + var newTag = tag.toBuilder(); + newTag.remove("color"); + return state.toBaseBlock(LazyReference.computed(newTag.build())); } private String convertBedType(int oldType) { - String color; - switch (oldType) { - case 0: - color = "white"; - break; - case 1: - color = "orange"; - break; - case 2: - color = "magenta"; - break; - case 3: - color = "light_blue"; - break; - case 4: - color = "yellow"; - break; - case 5: - color = "lime"; - break; - case 6: - color = "pink"; - break; - case 7: - color = "gray"; - break; - case 8: - color = "light_gray"; - break; - case 9: - color = "cyan"; - break; - case 10: - color = "purple"; - break; - case 11: - color = "blue"; - break; - case 12: - color = "brown"; - break; - case 13: - color = "green"; - break; - case 14: - color = "red"; - break; - case 15: - color = "black"; - break; - default: - return null; - } - return color + "_bed"; + String color = switch (oldType) { + case 0 -> "white"; + case 1 -> "orange"; + case 2 -> "magenta"; + case 3 -> "light_blue"; + case 4 -> "yellow"; + case 5 -> "lime"; + case 6 -> "pink"; + case 7 -> "gray"; + case 8 -> "light_gray"; + case 9 -> "cyan"; + case 10 -> "purple"; + case 11 -> "blue"; + case 12 -> "brown"; + case 13 -> "green"; + case 14 -> "red"; + case 15 -> "black"; + default -> null; + }; + return color == null ? null : color + "_bed"; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java index 6fcc6f422..cfd82833d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java @@ -20,12 +20,48 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; import com.sk89q.worldedit.world.entity.EntityType; +import org.enginehub.linbus.tree.LinCompoundTag; public interface EntityNBTCompatibilityHandler { - boolean isAffectedEntity(EntityType type, CompoundTag entityTag); + /** + * Check if this is an entity affected by this handler. + * + * @deprecated this was never used, just return the same tag from + * {@link #updateNbt(EntityType, LinCompoundTag)} if it's not affected + */ + @Deprecated + default boolean isAffectedEntity(EntityType type, CompoundTag entityTag) { + var original = entityTag.toLinTag(); + var updated = updateNbt(type, original); + return !original.equals(updated); + } - CompoundTag updateNBT(EntityType type, CompoundTag entityTag); + @Deprecated + default CompoundTag updateNBT(EntityType type, CompoundTag entityTag) { + return new CompoundTag(updateNbt(type, entityTag.toLinTag())); + } + /** + * Given an entity type and data, update the data if needed. + * + * @param type the entity type + * @param entityTag the entity tag + * @return the updated tag, or the same tag if no update was needed + * @apiNote This must be overridden by new subclasses. See {@link NonAbstractForCompatibility} + * for details + */ + @SuppressWarnings("deprecation") + @NonAbstractForCompatibility( + delegateName = "updateNBT", + delegateParams = { EntityType.class, CompoundTag.class } + ) + default LinCompoundTag updateNbt(EntityType type, LinCompoundTag entityTag) { + DeprecationUtil.checkDelegatingOverride(getClass()); + + return updateNBT(type, new CompoundTag(entityTag)).toLinTag(); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java index 95d2fb091..803b6c237 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java @@ -19,65 +19,50 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; -import com.sk89q.jnbt.IntTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; - -import java.util.Map; +import org.enginehub.linbus.tree.LinTagType; public class FlowerPotCompatibilityHandler implements NBTCompatibilityHandler { @Override - public > boolean isAffectedBlock(B block) { - return block.getBlockType() == BlockTypes.FLOWER_POT; - } - - @Override - public > BlockStateHolder updateNBT(B block, Map values) { - Tag item = values.get("Item"); - if (item instanceof StringTag) { - String id = ((StringTag) item).getValue(); - if (id.isEmpty()) { - return BlockTypes.FLOWER_POT.getDefaultState(); - } - int data = 0; - Tag dataTag = values.get("Data"); - if (dataTag instanceof IntTag) { - data = ((IntTag) dataTag).getValue(); - } - BlockState newState = convertLegacyBlockType(id, data); - if (newState != null) { - values.clear(); - return newState; - } + public BaseBlock updateNbt(BaseBlock block) { + if (block.getBlockType() != BlockTypes.FLOWER_POT) { + return block; } - return block; + var tag = block.getNbt(); + if (tag == null) { + return block; + } + var item = tag.findTag("Item", LinTagType.stringTag()); + if (item == null) { + return block; + } + String id = item.value(); + if (id.isEmpty()) { + return BlockTypes.FLOWER_POT.getDefaultState().toBaseBlock(); + } + int data = 0; + var dataTag = tag.findTag("Data", LinTagType.intTag()); + if (dataTag != null) { + data = dataTag.valueAsInt(); + } + BlockState newState = convertLegacyBlockType(id, data); + return newState != null ? newState.toBaseBlock() : block; } private BlockState convertLegacyBlockType(String id, int data) { - int newId = 0; - switch (id) { - case "minecraft:red_flower": - newId = 38; // now poppy - break; - case "minecraft:yellow_flower": - newId = 37; // now dandelion - break; - case "minecraft:sapling": - newId = 6; // oak_sapling - break; - case "minecraft:deadbush": - case "minecraft:tallgrass": - newId = 31; // dead_bush with fern and grass (not 32!) - break; - default: - break; - } + int newId = switch (id) { + case "minecraft:red_flower" -> 38; // now poppy + case "minecraft:yellow_flower" -> 37; // now dandelion + case "minecraft:sapling" -> 6; // oak_sapling + case "minecraft:deadbush", "minecraft:tallgrass" -> + 31; // dead_bush with fern and grass (not 32!) + default -> 0; + }; String plantedName = null; if (newId == 0 && id.startsWith("minecraft:")) { plantedName = id.substring(10); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NBTCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NBTCompatibilityHandler.java index b7093dd4d..a2d32ea93 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NBTCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NBTCompatibilityHandler.java @@ -19,15 +19,80 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; +import org.enginehub.linbus.tree.LinCompoundTag; +import java.util.HashMap; import java.util.Map; public interface NBTCompatibilityHandler { - > boolean isAffectedBlock(B block); + /** + * Check if this is a block affected by this handler. + * + * @deprecated this is handled by {@link #updateNbt(BaseBlock)} now + */ + @Deprecated + default > boolean isAffectedBlock(B block) { + BaseBlock state = block.toBaseBlock(); + BaseBlock updated = updateNbt(state); + return state != updated; + } - > BlockStateHolder updateNBT(B block, Map values); + @Deprecated + default > BlockStateHolder updateNBT(B block, Map> values) { + BaseBlock changed = updateNbt(block.toBaseBlock(LazyReference.from(() -> { + var builder = LinCompoundTag.builder(); + for (var entry : values.entrySet()) { + builder.put(entry.getKey(), entry.getValue().toLinTag()); + } + return builder.build(); + }))); + CompoundTag data = changed.getNbtData(); + values.clear(); + if (data != null) { + values.putAll(data.getValue()); + } + return changed; + } + + /** + * Given a block, update the block's NBT. The NBT may be {@code null}. + * + * @param block the block to update + * @return the updated block, or the same block if no change is necessary + * @apiNote This must be overridden by new subclasses. See {@link NonAbstractForCompatibility} + * for details + */ + @NonAbstractForCompatibility( + delegateName = "updateNBT", + delegateParams = { BlockStateHolder.class, Map.class } + ) + @SuppressWarnings("deprecated") + default BaseBlock updateNbt(BaseBlock block) { + DeprecationUtil.checkDelegatingOverride(getClass()); + if (!isAffectedBlock(block)) { + return block; + } + if (block.getNbt() == null) { + return block; + } + @SuppressWarnings("deprecation") + Map> values = new HashMap<>(new CompoundTag(block.getNbt()).getValue()); + BlockStateHolder changedBlock = updateNBT(block, values); + return changedBlock.toBaseBlock(LazyReference.from(() -> { + var builder = LinCompoundTag.builder(); + for (var entry : values.entrySet()) { + builder.put(entry.getKey(), entry.getValue().toLinTag()); + } + return builder.build(); + })); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java index 508e84280..04190197e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java @@ -19,18 +19,15 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; -import com.sk89q.jnbt.ByteTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.registry.state.IntegerProperty; import com.sk89q.worldedit.registry.state.Property; -import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; - -import java.util.Map; +import org.enginehub.linbus.tree.LinTagType; public class NoteBlockCompatibilityHandler implements NBTCompatibilityHandler { - private static final IntegerProperty NoteProperty; + private static final IntegerProperty NOTE_PROPERTY; static { IntegerProperty temp; @@ -39,27 +36,25 @@ public class NoteBlockCompatibilityHandler implements NBTCompatibilityHandler { } catch (NullPointerException | IllegalArgumentException | ClassCastException e) { temp = null; } - NoteProperty = temp; + NOTE_PROPERTY = temp; } @Override - public > boolean isAffectedBlock(B block) { - return NoteProperty != null && block.getBlockType() == BlockTypes.NOTE_BLOCK; - } - - @Override - public > BlockStateHolder updateNBT(B block, Map values) { + public BaseBlock updateNbt(BaseBlock block) { + if (NOTE_PROPERTY == null || block.getBlockType() != BlockTypes.NOTE_BLOCK) { + return block; + } + var tag = block.getNbt(); + if (tag == null) { + return block; + } // note that instrument was not stored (in state or nbt) previously. // it will be updated to the block below when it gets set into the world for the first time - Tag noteTag = values.get("note"); - if (noteTag instanceof ByteTag) { - Byte note = ((ByteTag) noteTag).getValue(); - if (note != null) { - values.clear(); - return block.with(NoteProperty, (int) note).toImmutableState(); - } + var noteTag = tag.findTag("note", LinTagType.byteTag()); + if (noteTag == null) { + return block; } - return block; + return block.with(NOTE_PROPERTY, (int) noteTag.valueAsByte()).toBaseBlock(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java index 346f5f29e..f0bea016f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java @@ -19,41 +19,31 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.CompoundTagBuilder; import com.sk89q.worldedit.internal.helper.MCDirections; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.world.entity.EntityType; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinNumberTag; public class Pre13HangingCompatibilityHandler implements EntityNBTCompatibilityHandler { @Override - public boolean isAffectedEntity(EntityType type, CompoundTag tag) { - if (!type.id().startsWith("minecraft:")) { - return false; + public LinCompoundTag updateNbt(EntityType type, LinCompoundTag tag) { + if (!type.getId().startsWith("minecraft:")) { + return tag; } - boolean hasLegacyDirection = tag.containsKey("Dir") || tag.containsKey("Direction"); - boolean hasFacing = tag.containsKey("Facing"); - return hasLegacyDirection || hasFacing; - } - - @Override - public CompoundTag updateNBT(EntityType type, CompoundTag tag) { - boolean hasLegacyDir = tag.containsKey("Dir"); - boolean hasLegacyDirection = tag.containsKey("Direction"); - boolean hasPre113Facing = tag.containsKey("Facing"); Direction newDirection; - if (hasLegacyDir) { - newDirection = MCDirections.fromPre13Hanging(MCDirections.fromLegacyHanging((byte) tag.asInt("Dir"))); - } else if (hasLegacyDirection) { - newDirection = MCDirections.fromPre13Hanging(tag.asInt("Direction")); - } else if (hasPre113Facing) { - newDirection = MCDirections.fromPre13Hanging(tag.asInt("Facing")); + if (tag.value().get("Dir") instanceof LinNumberTag legacyDir) { + newDirection = MCDirections.fromPre13Hanging(MCDirections.fromLegacyHanging(legacyDir.value().byteValue())); + } else if (tag.value().get("Direction") instanceof LinNumberTag legacyDirection) { + newDirection = MCDirections.fromPre13Hanging(legacyDirection.value().intValue()); + } else if (tag.value().get("Facing") instanceof LinNumberTag legacyFacing) { + newDirection = MCDirections.fromPre13Hanging(legacyFacing.value().intValue()); } else { return tag; } byte hangingByte = (byte) MCDirections.toHanging(newDirection); - CompoundTagBuilder builder = tag.createBuilder(); + var builder = tag.toBuilder(); builder.putByte("Facing", hangingByte); return builder.build(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SignCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SignCompatibilityHandler.java index d2dd4f5a8..24c5de232 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SignCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SignCompatibilityHandler.java @@ -24,50 +24,52 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSyntaxException; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.internal.util.DeprecationUtil; -import com.sk89q.worldedit.world.block.BlockStateHolder; - -import java.util.Map; +import com.sk89q.worldedit.world.block.BaseBlock; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTagType; public class SignCompatibilityHandler implements NBTCompatibilityHandler { @Override - public > boolean isAffectedBlock(B block) { - return DeprecationUtil.isSign(block.getBlockType()); - } - - @Override - public > BlockStateHolder updateNBT(B block, Map values) { + public BaseBlock updateNbt(BaseBlock block) { + if (!DeprecationUtil.isSign(block.getBlockType())) { + return block; + } + var tag = block.getNbt(); + if (tag == null) { + return block; + } + var newTag = tag.toBuilder(); for (int i = 0; i < 4; ++i) { String key = "Text" + (i + 1); - Tag value = values.get(key); - if (value instanceof StringTag) { - String storedString = ((StringTag) value).getValue(); - JsonElement jsonElement = null; - if (storedString != null && storedString.startsWith("{")) { - try { - jsonElement = new JsonParser().parse(storedString); - } catch (JsonSyntaxException ex) { - // ignore: jsonElement will be null in the next check - } - } - if (jsonElement == null) { - jsonElement = new JsonPrimitive(storedString == null ? "" : storedString); - } - if (jsonElement.isJsonObject()) { - continue; - } - - if (jsonElement.isJsonNull()) { - jsonElement = new JsonPrimitive(""); - } - - JsonObject jsonTextObject = new JsonObject(); - jsonTextObject.add("text", jsonElement); - values.put("Text" + (i + 1), new StringTag(jsonTextObject.toString())); + var value = tag.findTag(key, LinTagType.stringTag()); + if (value == null) { + continue; } + String storedString = value.value(); + JsonElement jsonElement = null; + if (storedString.startsWith("{")) { + try { + jsonElement = JsonParser.parseString(storedString); + } catch (JsonSyntaxException ex) { + // ignore: jsonElement will be null in the next check + } + } + if (jsonElement == null) { + jsonElement = new JsonPrimitive(storedString); + } + if (jsonElement.isJsonObject()) { + continue; + } + + if (jsonElement.isJsonNull()) { + jsonElement = new JsonPrimitive(""); + } + + JsonObject jsonTextObject = new JsonObject(); + jsonTextObject.add("text", jsonElement); + newTag.put("Text" + (i + 1), LinStringTag.of(jsonTextObject.toString())); } return block; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java index f00622561..6d5158208 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java @@ -19,20 +19,17 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; -import com.sk89q.jnbt.ByteTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; - -import java.util.Map; +import org.enginehub.linbus.tree.LinTagType; public class SkullBlockCompatibilityHandler implements NBTCompatibilityHandler { - private static final Property FacingProperty; + private static final Property FACING_PROPERTY; static { Property tempFacing; @@ -41,61 +38,70 @@ public class SkullBlockCompatibilityHandler implements NBTCompatibilityHandler { } catch (NullPointerException | IllegalArgumentException | ClassCastException e) { tempFacing = null; } - FacingProperty = tempFacing; + FACING_PROPERTY = tempFacing; } @Override - public > boolean isAffectedBlock(B block) { - return block.getBlockType() == BlockTypes.SKELETON_SKULL - || block.getBlockType() == BlockTypes.SKELETON_WALL_SKULL; - } - - @Override - public > BlockStateHolder updateNBT(B block, Map values) { - boolean isWall = block.getBlockType() == BlockTypes.SKELETON_WALL_SKULL; - Tag typeTag = values.get("SkullType"); - if (typeTag instanceof ByteTag) { - String skullType = convertSkullType(((ByteTag) typeTag).getValue(), isWall); - if (skullType != null) { - BlockType type = BlockTypes.get("minecraft:" + skullType); - if (type != null) { - BlockState state = type.getDefaultState(); - if (isWall) { - Property newProp = type.getProperty("facing"); - state = state.with(newProp, block.getState(FacingProperty)); - } else { - Tag rotTag = values.get("Rot"); - if (rotTag instanceof ByteTag) { - Property newProp = type.getProperty("rotation"); - state = state.with(newProp, (int) ((ByteTag) rotTag).getValue()); - } - } - values.remove("SkullType"); - values.remove("Rot"); - return state; - } + public BaseBlock updateNbt(BaseBlock block) { + var blockType = block.getBlockType(); + boolean isWall = blockType == BlockTypes.SKELETON_WALL_SKULL; + if (blockType != BlockTypes.SKELETON_SKULL && !isWall) { + return block; + } + if (FACING_PROPERTY == null) { + return block; + } + var tag = block.getNbt(); + if (tag == null) { + return block; + } + var typeTag = tag.findTag("SkullType", LinTagType.byteTag()); + if (typeTag == null) { + return block; + } + String skullType = convertSkullType(typeTag.valueAsByte(), isWall); + if (skullType == null) { + return block; + } + BlockType type = BlockTypes.get("minecraft:" + skullType); + if (type == null) { + return block; + } + BlockState state = type.getDefaultState(); + if (isWall) { + Property newProp = type.getProperty("facing"); + state = state.with(newProp, block.getState(FACING_PROPERTY)); + } else { + var rotTag = tag.findTag("Rot", LinTagType.byteTag()); + if (rotTag != null) { + Property newProp = type.getProperty("rotation"); + state = state.with(newProp, (int) rotTag.valueAsByte()); } } - return block; + var newTag = tag.toBuilder() + .remove("SkullType") + .remove("Rot") + .build(); + return state.toBaseBlock(newTag); } - private String convertSkullType(Byte oldType, boolean isWall) { - switch (oldType) { - case 0: - return isWall ? "skeleton_wall_skull" : "skeleton_skull"; - case 1: - return isWall ? "wither_skeleton_wall_skull" : "wither_skeleton_skull"; - case 2: - return isWall ? "zombie_wall_head" : "zombie_head"; - case 3: - return isWall ? "player_wall_head" : "player_head"; - case 4: - return isWall ? "creeper_wall_head" : "creeper_head"; - case 5: - return isWall ? "dragon_wall_head" : "dragon_head"; - default: - return null; + private String convertSkullType(byte oldType, boolean isWall) { + record SkullData(String kind, String suffix) { } + + var skullData = switch (oldType) { + case 0 -> new SkullData("skeleton", "skull"); + case 1 -> new SkullData("wither_skeleton", "skull"); + case 2 -> new SkullData("zombie", "head"); + case 3 -> new SkullData("player", "head"); + case 4 -> new SkullData("creeper", "head"); + case 5 -> new SkullData("dragon", "head"); + default -> null; + }; + if (skullData == null) { + return null; + } + return skullData.kind + (isWall ? "_wall" : "") + "_" + skullData.suffix; } } 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 5f434cf9b..519463760 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 @@ -401,7 +401,7 @@ public class BlockTransformExtent extends ResettableExtent { ); if (newDirection != null) { - Map values = new HashMap<>(tag.getValue()); + Map> values = new HashMap<>(tag.getValue()); values.put("Rot", new ByteTag((byte) MCDirections.toRotation(newDirection))); tag = new CompoundTag(values); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java index 88cf4fc6f..b2670113a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java @@ -26,9 +26,9 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockStateHolder; +import org.enginehub.linbus.tree.LinCompoundTag; import java.util.Collection; @@ -115,9 +115,7 @@ public class SurvivalModeExtent extends AbstractDelegateExtent { } else { // Can't be an inlined check due to inconsistent generic return type if (stripNbt) { - //FAWE start - Use CompoundBinaryTag - return super.setBlock(location, block.toBaseBlock((CompoundBinaryTag) null)); - //FAWE end + return super.setBlock(location, block.toBaseBlock((LinCompoundTag) null)); } else { return super.setBlock(location, block); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java index 093a7737f..e4b390797 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java @@ -28,10 +28,9 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction.Flag; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.NumberBinaryTag; import com.sk89q.worldedit.world.block.BaseBlock; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinTag; import static com.google.common.base.Preconditions.checkNotNull; @@ -88,14 +87,13 @@ public class ExtentBlockCopy implements RegionFunction { * @return a new state or the existing one */ private BaseBlock transformNbtData(BaseBlock state) { - //FAWE start - Replace CompoundTag with CompoundBinaryTag - CompoundBinaryTag tag = state.getNbt(); + LinCompoundTag tag = state.getNbt(); if (tag != null) { // Handle blocks which store their rotation in NBT - BinaryTag rotTag = tag.get("Rot"); - if (rotTag instanceof NumberBinaryTag) { - int rot = ((NumberBinaryTag) rotTag).intValue(); + LinTag rotTag = tag.value().get("Rot"); + if (rotTag.value() instanceof Number number) { + int rot = number.intValue(); Direction direction = MCDirections.fromRotation(rot); @@ -105,8 +103,9 @@ public class ExtentBlockCopy implements RegionFunction { if (newDirection != null) { return state.toBaseBlock( - tag.putByte("Rot", (byte) MCDirections.toRotation(newDirection)) - //FAWE end + tag.toBuilder() + .putByte("Rot", (byte) MCDirections.toRotation(newDirection)) + .build() ); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java index c30f6fa4d..49fac779a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java @@ -29,9 +29,9 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; @@ -135,9 +135,6 @@ public class ServerCUIHandler { Math.min(Math.min(player.getWorld().getMaxY(), posY + MAX_DISTANCE), posY + 3) ); - //FAWE start - CBT > Map - CompoundBinaryTag.Builder structureTag = CompoundBinaryTag.builder(); - posX -= x; posY -= y; posZ -= z; @@ -147,7 +144,7 @@ public class ServerCUIHandler { return null; } - //FAWE start - see comment of CBT + LinCompoundTag.Builder structureTag = LinCompoundTag.builder(); structureTag.putString("name", "worldedit:" + player.getName()); structureTag.putString("author", player.getName()); structureTag.putString("metadata", ""); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java index aa90cb816..56cab805f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java @@ -19,17 +19,14 @@ package com.sk89q.worldedit.internal.wna; -import com.google.common.collect.ImmutableMap; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; @@ -68,17 +65,15 @@ public interface WorldNativeAccess { // Create the TileEntity if (successful || old == newState) { - if (block instanceof BaseBlock) { - BaseBlock baseBlock = (BaseBlock) block; - //FAWE start - use CompoundBinaryTag over CompoundTag - CompoundBinaryTag tag = baseBlock.getNbt(); + if (block instanceof BaseBlock baseBlock) { + LinCompoundTag tag = baseBlock.getNbt(); if (tag != null) { - tag = tag.put(ImmutableMap.of( - "id", StringBinaryTag.of(baseBlock.getNbtId()), - "x", IntBinaryTag.of(position.x()), - "y", IntBinaryTag.of(position.y()), - "z", IntBinaryTag.of(position.z()) - )); + tag = tag.toBuilder() + .putString("id", baseBlock.getNbtId()) + .putInt("x", position.getX()) + .putInt("y", position.getY()) + .putInt("z", position.getZ()) + .build(); // update if TE changed as well successful = updateTileEntity(pos, tag); @@ -143,7 +138,7 @@ public interface WorldNativeAccess { void updateLightingForBlock(NP position); - boolean updateTileEntity(NP position, CompoundBinaryTag tag); + boolean updateTileEntity(NP position, LinCompoundTag tag); void notifyBlockUpdate(NC chunk, NP position, NBS oldState, NBS newState); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java index 5b69ddff0..414190a98 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java @@ -20,8 +20,7 @@ package com.sk89q.worldedit.world; import com.google.common.annotations.Beta; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import org.enginehub.linbus.tree.LinCompoundTag; /** * This entire class is subject to heavy changes. Do not use this as API. @@ -41,15 +40,12 @@ public interface DataFixer { private FixTypes() { } - //FAWE start - BinaryTag - public static FixType CHUNK = new FixType<>(); - public static FixType BLOCK_ENTITY = new FixType<>(); - public static FixType ENTITY = new FixType<>(); - //FAWE end - public static FixType BLOCK_STATE = new FixType<>(); - public static FixType BIOME = new FixType<>(); - public static FixType ITEM_TYPE = new FixType<>(); - + public static final FixType CHUNK = new FixType<>(); + public static final FixType BLOCK_ENTITY = new FixType<>(); + public static final FixType ENTITY = new FixType<>(); + public static final FixType BLOCK_STATE = new FixType<>(); + public static final FixType BIOME = new FixType<>(); + public static final FixType ITEM_TYPE = new FixType<>(); } default T fixUp(FixType type, T original) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NbtValued.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NbtValued.java index a85868685..e1c5d6de0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NbtValued.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NbtValued.java @@ -23,7 +23,7 @@ import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.internal.util.DeprecationUtil; import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; @@ -66,7 +66,7 @@ public interface NbtValued { @Deprecated @Nullable default CompoundTag getNbtData() { - CompoundBinaryTag tag = getNbt(); + LinCompoundTag tag = getNbt(); return tag == null ? null : new CompoundTag(tag); } @@ -78,7 +78,7 @@ public interface NbtValued { */ @Deprecated default void setNbtData(@Nullable CompoundTag nbtData) { - setNbtReference(nbtData == null ? null : LazyReference.from(nbtData::asBinaryTag)); + setNbtReference(nbtData == null ? null : LazyReference.from(nbtData::toLinTag)); } /** @@ -96,11 +96,12 @@ public interface NbtValued { delegateParams = {} ) @Nullable - default LazyReference getNbtReference() { + default LazyReference getNbtReference() { DeprecationUtil.checkDelegatingOverride(getClass()); + @SuppressWarnings("deprecation") CompoundTag nbtData = getNbtData(); - return nbtData == null ? null : LazyReference.from(nbtData::asBinaryTag); + return nbtData == null ? null : LazyReference.from(nbtData::toLinTag); } /** @@ -109,8 +110,8 @@ public interface NbtValued { * @return compound tag, or null */ @Nullable - default CompoundBinaryTag getNbt() { - LazyReference ref = getNbtReference(); + default LinCompoundTag getNbt() { + LazyReference ref = getNbtReference(); return ref == null ? null : ref.getValue(); } @@ -119,11 +120,12 @@ public interface NbtValued { * * @param nbtData NBT data, or null if no data */ + @SuppressWarnings("deprecation") @NonAbstractForCompatibility( delegateName = "setNbtData", delegateParams = {CompoundTag.class} ) - default void setNbtReference(@Nullable LazyReference nbtData) { + default void setNbtReference(@Nullable LazyReference nbtData) { DeprecationUtil.checkDelegatingOverride(getClass()); setNbtData(nbtData == null ? null : new CompoundTag(nbtData.getValue())); @@ -134,7 +136,7 @@ public interface NbtValued { * * @param nbtData NBT data, or null if no data */ - default void setNbt(@Nullable CompoundBinaryTag nbtData) { + default void setNbt(@Nullable LinCompoundTag nbtData) { setNbtReference(nbtData == null ? null : LazyReference.computed(nbtData)); } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java index 9828c9069..ab93a4016 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.world.block; import com.fastasyncworldedit.core.registry.state.PropertyKey; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.TileEntityBlock; import com.sk89q.worldedit.extent.Extent; @@ -29,13 +28,13 @@ import com.sk89q.worldedit.extent.OutputExtent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.TagStringIO; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.LegacyMapper; +import org.enginehub.linbus.format.snbt.LinStringIO; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinTagType; import javax.annotation.Nullable; -import java.io.IOException; import java.util.Map; import java.util.Objects; @@ -54,7 +53,7 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { private final BlockState blockState; @Nullable - private final LazyReference nbtData; + private final LazyReference nbtData; //FAWE start @@ -93,7 +92,7 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { */ @Deprecated public BaseBlock(BlockState state, CompoundTag nbtData) { - this(state, LazyReference.from(checkNotNull(nbtData)::asBinaryTag)); + this(state, LazyReference.from(checkNotNull(nbtData)::toLinTag)); } //FAWE end @@ -104,7 +103,7 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { * @param state The block state * @param nbtData NBT data, which must be provided */ - protected BaseBlock(BlockState state, LazyReference nbtData) { + protected BaseBlock(BlockState state, LazyReference nbtData) { checkNotNull(nbtData); this.blockState = state; this.nbtData = nbtData; @@ -165,21 +164,21 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { @Override public String getNbtId() { - LazyReference nbtData = this.nbtData; + LazyReference nbtData = this.nbtData; if (nbtData == null) { return ""; } - return nbtData.getValue().getString("id"); + return nbtData.getValue().getTag("id", LinTagType.stringTag()).value(); } @Nullable @Override - public LazyReference getNbtReference() { + public LazyReference getNbtReference() { return this.nbtData; } @Override - public void setNbtReference(@Nullable LazyReference nbtData) { + public void setNbtReference(@Nullable LazyReference nbtData) { throw new UnsupportedOperationException("This class is immutable."); } @@ -244,7 +243,7 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { } @Override - public BaseBlock toBaseBlock(LazyReference compoundTag) { + public BaseBlock toBaseBlock(LazyReference compoundTag) { if (compoundTag == null) { return this.blockState.toBaseBlock(); } else if (compoundTag == this.nbtData) { @@ -300,20 +299,20 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { @Override public int hashCode() { - return getOrdinal(); + int ret = getOrdinal() << 3; + LinCompoundTag nbtData = getNbt(); + if (nbtData != null) { + ret += nbtData.hashCode(); + } + return ret; } //FAWE end @Override public String toString() { String nbtString = ""; - CompoundBinaryTag nbtData = getNbt(); if (nbtData != null) { - try { - nbtString = TagStringIO.get().asString(nbtData); - } catch (IOException e) { - WorldEdit.logger.error("Failed to serialize NBT of Block", e); - } + nbtString = LinStringIO.writeToString(nbtData.getValue()); } return blockState.getAsString() + nbtString; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index 713204843..caa8ba919 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -45,8 +45,8 @@ import com.sk89q.worldedit.registry.state.AbstractProperty; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.TextComponent; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.registry.BlockMaterial; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -420,7 +420,7 @@ public class BlockState implements BlockStateHolder, Pattern { //FAWE end @Override - public BaseBlock toBaseBlock(LazyReference compoundTag) { + public BaseBlock toBaseBlock(LazyReference compoundTag) { if (compoundTag == null) { return toBaseBlock(); } 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 e40482302..f2ea08b67 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 @@ -30,8 +30,8 @@ import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.registry.BlockMaterial; +import org.enginehub.linbus.tree.LinCompoundTag; import java.util.Locale; import java.util.Map; @@ -158,7 +158,7 @@ public interface BlockStateHolder> extends TileEnt */ @Deprecated default BaseBlock toBaseBlock(CompoundTag compoundTag) { - return toBaseBlock(compoundTag == null ? null : LazyReference.from(compoundTag::asBinaryTag)); + return toBaseBlock(compoundTag == null ? null : LazyReference.from(compoundTag::toLinTag)); } /** @@ -169,11 +169,12 @@ public interface BlockStateHolder> extends TileEnt * This must be overridden by new subclasses. See {@link NonAbstractForCompatibility} * for details */ + @SuppressWarnings("deprecation") @NonAbstractForCompatibility( delegateName = "toBaseBlock", delegateParams = {CompoundTag.class} ) - default BaseBlock toBaseBlock(LazyReference compoundTag) { + default BaseBlock toBaseBlock(LazyReference compoundTag) { DeprecationUtil.checkDelegatingOverride(getClass()); return toBaseBlock(compoundTag == null ? null : new CompoundTag(compoundTag.getValue())); @@ -185,7 +186,7 @@ public interface BlockStateHolder> extends TileEnt * @param compoundTag The NBT Data to apply * @return The BaseBlock */ - default BaseBlock toBaseBlock(CompoundBinaryTag compoundTag) { + default BaseBlock toBaseBlock(LinCompoundTag compoundTag) { return toBaseBlock(compoundTag == null ? null : LazyReference.computed(compoundTag)); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java index 5535f4305..8a3c3de89 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java @@ -19,21 +19,20 @@ package com.sk89q.worldedit.world.chunk; -import com.fastasyncworldedit.core.util.NbtUtils; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; import com.sk89q.worldedit.world.storage.InvalidFormatException; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import javax.annotation.Nullable; import java.util.HashMap; @@ -41,25 +40,25 @@ import java.util.Map; public class AnvilChunk implements Chunk { - private final CompoundBinaryTag rootTag; + private final LinCompoundTag rootTag; private final byte[][] blocks; private final byte[][] blocksAdd; private final byte[][] data; private final int rootX; private final int rootZ; - private Map tileEntities; + private Map tileEntities; /** * Construct the chunk with a compound tag. * * @param tag the tag to read * @throws DataException on a data error - * @deprecated Use {@link #AnvilChunk(CompoundBinaryTag)} + * @deprecated Use {@link #AnvilChunk(LinCompoundTag)} */ @Deprecated public AnvilChunk(CompoundTag tag) throws DataException { - this(tag.asBinaryTag()); + this(tag.toLinTag()); } /** @@ -68,45 +67,40 @@ public class AnvilChunk implements Chunk { * @param tag the tag to read * @throws DataException on a data error */ - public AnvilChunk(CompoundBinaryTag tag) throws DataException { + public AnvilChunk(LinCompoundTag tag) throws DataException { rootTag = tag; - rootX = NbtUtils.getChildTag(rootTag, "xPos", BinaryTagTypes.INT).value(); - rootZ = NbtUtils.getChildTag(rootTag, "zPos", BinaryTagTypes.INT).value(); + rootX = rootTag.getTag("xPos", LinTagType.intTag()).value(); + rootZ = rootTag.getTag("zPos", LinTagType.intTag()).value(); blocks = new byte[16][16 * 16 * 16]; blocksAdd = new byte[16][16 * 16 * 8]; data = new byte[16][16 * 16 * 8]; - ListBinaryTag sections = NbtUtils.getChildTag(rootTag, "Sections", BinaryTagTypes.LIST); + LinListTag> sections = rootTag.getTag("Sections", LinTagType.listTag()); - for (BinaryTag rawSectionTag : sections) { - if (!(rawSectionTag instanceof CompoundBinaryTag)) { + for (LinTag rawSectionTag : sections.value()) { + if (!(rawSectionTag instanceof LinCompoundTag sectionTag)) { continue; } - CompoundBinaryTag sectionTag = (CompoundBinaryTag) rawSectionTag; - if (sectionTag.get("Y") == null) { + var sectionYTag = sectionTag.findTag("Y", LinTagType.byteTag()); + if (sectionYTag == null) { continue; // Empty section. } - int y = NbtUtils.getChildTag(sectionTag, "Y", BinaryTagTypes.BYTE).value(); + int y = sectionYTag.value(); if (y < 0 || y >= 16) { continue; } - blocks[y] = NbtUtils.getChildTag(sectionTag, - "Blocks", BinaryTagTypes.BYTE_ARRAY - ).value(); - data[y] = NbtUtils.getChildTag(sectionTag, "Data", - BinaryTagTypes.BYTE_ARRAY - ).value(); + blocks[y] = sectionTag.getTag("Blocks", LinTagType.byteArrayTag()).value(); + data[y] = sectionTag.getTag("Data", LinTagType.byteArrayTag()).value(); // 4096 ID block support - if (sectionTag.get("Add") != null) { - blocksAdd[y] = NbtUtils.getChildTag(sectionTag, - "Add", BinaryTagTypes.BYTE_ARRAY - ).value(); + var addTag = sectionTag.findTag("Add", LinTagType.byteArrayTag()); + if (addTag != null) { + blocksAdd[y] = addTag.value(); } } @@ -144,17 +138,12 @@ public class AnvilChunk implements Chunk { int index = x + (z * 16 + (yindex * 16 * 16)); try { - int addId = 0; - // The block ID is the combination of the Blocks byte array with the // Add byte array. 'Blocks' stores the lowest 8 bits of a block's ID, and // 'Add' stores the highest 4 bits of the ID. The first block is stored // in the lowest nibble in the Add byte array. - if (index % 2 == 0) { - addId = (blocksAdd[section][index >> 1] & 0x0F) << 8; - } else { - addId = (blocksAdd[section][index >> 1] & 0xF0) << 4; - } + byte addByte = blocksAdd[section][index >> 1]; + int addId = (index & 1) == 0 ? (addByte & 0x0F) << 8 : (addByte & 0xF0) << 4; return (blocks[section][index] & 0xFF) + addId; } catch (IndexOutOfBoundsException e) { @@ -175,15 +164,12 @@ public class AnvilChunk implements Chunk { } int index = x + (z * 16 + (yIndex * 16 * 16)); - boolean shift = index % 2 == 0; - index /= 2; + boolean shift = (index & 1) != 0; + index >>= 2; try { - if (!shift) { - return (data[section][index] & 0xF0) >> 4; - } else { - return data[section][index] & 0xF; - } + byte dataByte = data[section][index]; + return shift ? (dataByte & 0xF0) >> 4 : dataByte & 0x0F; } catch (IndexOutOfBoundsException e) { throw new DataException("Chunk does not contain position " + position); } @@ -192,44 +178,40 @@ public class AnvilChunk implements Chunk { /** * Used to load the tile entities. */ - private void populateTileEntities() throws DataException { - ListBinaryTag tags = NbtUtils.getChildTag(rootTag, "TileEntities", BinaryTagTypes.LIST); + private void populateTileEntities() { + LinListTag tags = rootTag.getTag("TileEntities", LinTagType.listTag()) + .asTypeChecked(LinTagType.compoundTag()); - tileEntities = new HashMap<>(); - - for (BinaryTag tag : tags) { - if (!(tag instanceof CompoundBinaryTag)) { - throw new InvalidFormatException("CompoundTag expected in TileEntities"); - } - - CompoundBinaryTag t = (CompoundBinaryTag) tag; + tileEntities = new HashMap<>(tags.value().size()); + for (LinCompoundTag t : tags.value()) { int x = 0; int y = 0; int z = 0; - CompoundBinaryTag.Builder values = CompoundBinaryTag.builder(); + LinCompoundTag.Builder values = LinCompoundTag.builder(); - for (String key : t.keySet()) { - BinaryTag value = t.get(key); + for (String key : t.value().keySet()) { + LinTag value = t.value().get(key); switch (key) { - case "x": - if (value instanceof IntBinaryTag) { - x = ((IntBinaryTag) value).value(); + case "x" -> { + if (value instanceof LinIntTag v) { + x = v.valueAsInt(); } - break; - case "y": - if (value instanceof IntBinaryTag) { - y = ((IntBinaryTag) value).value(); + } + case "y" -> { + if (value instanceof LinIntTag v) { + y = v.valueAsInt(); } - break; - case "z": - if (value instanceof IntBinaryTag) { - z = ((IntBinaryTag) value).value(); + } + case "z" -> { + if (value instanceof LinIntTag v) { + z = v.valueAsInt(); } - break; - default: - break; + } + default -> { + // Do nothing. + } } values.put(key, value); @@ -250,14 +232,12 @@ public class AnvilChunk implements Chunk { * @throws DataException thrown if there is a data error */ @Nullable - private CompoundBinaryTag getBlockTileEntity(BlockVector3 position) throws DataException { + private LinCompoundTag getBlockTileEntity(BlockVector3 position) throws DataException { if (tileEntities == null) { populateTileEntities(); } - CompoundBinaryTag values = tileEntities.get(position); - - return values; + return tileEntities.get(position); } @Override @@ -270,7 +250,7 @@ public class AnvilChunk implements Chunk { WorldEdit.logger.warn("Unknown legacy block " + id + ":" + data + " found when loading legacy anvil chunk."); return BlockTypes.AIR.getDefaultState().toBaseBlock(); } - CompoundBinaryTag tileEntity = getBlockTileEntity(position); + LinCompoundTag tileEntity = getBlockTileEntity(position); if (tileEntity != null) { return state.toBaseBlock(tileEntity); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java index a8c2d63c2..9b3d54027 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java @@ -19,17 +19,12 @@ package com.sk89q.worldedit.world.chunk; -import com.fastasyncworldedit.core.util.NbtUtils; +import com.google.common.collect.ImmutableMap; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; @@ -39,10 +34,14 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.storage.InvalidFormatException; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import javax.annotation.Nullable; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -51,26 +50,28 @@ import java.util.Map; */ public class AnvilChunk13 implements Chunk { - protected final CompoundBinaryTag rootTag; + protected final LinCompoundTag rootTag; + private final BlockState[][] blocks; //FAWE start - biome and entity restore protected BiomeType[] biomes; - //FAWE end - private Map tileEntities; - //FAWE start - biome and entity restore private List entities; //FAWE end + private Map tileEntities; + private final int rootX; + private final int rootZ; + /** * Construct the chunk with a compound tag. * * @param tag the tag to read * @throws DataException on a data error - * @deprecated Use {@link #AnvilChunk13(CompoundBinaryTag)} + * @deprecated Use {@link #AnvilChunk13(LinCompoundTag)} */ @Deprecated public AnvilChunk13(CompoundTag tag) throws DataException { - this(tag.asBinaryTag()); + this(tag.toLinTag()); } /** @@ -79,53 +80,58 @@ public class AnvilChunk13 implements Chunk { * @param tag the tag to read * @throws DataException on a data error */ - public AnvilChunk13(CompoundBinaryTag tag) throws DataException { + public AnvilChunk13(LinCompoundTag tag) throws DataException { rootTag = tag; + rootX = rootTag.getTag("xPos", LinTagType.intTag()).valueAsInt(); + rootZ = rootTag.getTag("zPos", LinTagType.intTag()).valueAsInt(); + blocks = new BlockState[16][]; - ListBinaryTag sections = NbtUtils.getChildTag(rootTag, "Sections", BinaryTagTypes.LIST); + LinListTag> sections = rootTag.getTag("Sections", LinTagType.listTag()); - for (BinaryTag rawSectionTag : sections) { - if (!(rawSectionTag instanceof CompoundBinaryTag)) { + for (LinTag rawSectionTag : sections.value()) { + if (!(rawSectionTag instanceof LinCompoundTag sectionTag)) { continue; } - CompoundBinaryTag sectionTag = (CompoundBinaryTag) rawSectionTag; - if (sectionTag.get("Y") == null) { + var sectionYTag = sectionTag.findTag("Y", LinTagType.byteTag()); + if (sectionYTag == null) { continue; // Empty section. } - int y = NbtUtils.getChildTag(sectionTag, "Y", BinaryTagTypes.BYTE).value(); + int y = sectionYTag.value(); if (y < 0 || y >= 16) { continue; } // parse palette - ListBinaryTag paletteEntries = sectionTag.getList("Palette", BinaryTagTypes.COMPOUND); - int paletteSize = paletteEntries.size(); + LinListTag paletteEntries = sectionTag.getTag( + "Palette", LinTagType.listTag() + ).asTypeChecked(LinTagType.compoundTag()); + int paletteSize = paletteEntries.value().size(); if (paletteSize == 0) { continue; } BlockState[] palette = new BlockState[paletteSize]; for (int paletteEntryId = 0; paletteEntryId < paletteSize; paletteEntryId++) { - CompoundBinaryTag paletteEntry = (CompoundBinaryTag) paletteEntries.get(paletteEntryId); - BlockType type = BlockTypes.get(paletteEntry.getString("Name")); + LinCompoundTag paletteEntry = paletteEntries.get(paletteEntryId); + String blockType = paletteEntry.getTag("Name", LinTagType.stringTag()).value(); + BlockType type = BlockTypes.get(blockType); if (type == null) { - throw new InvalidFormatException("Invalid block type: " + paletteEntry.getString("Name")); + throw new InvalidFormatException("Invalid block type: " + blockType); } BlockState blockState = type.getDefaultState(); - if (paletteEntry.get("Properties") != null) { - CompoundBinaryTag properties = NbtUtils.getChildTag(paletteEntry, "Properties", BinaryTagTypes.COMPOUND); + var propertiesTag = paletteEntry.findTag("Properties", LinTagType.compoundTag()); + if (propertiesTag != null) { for (Property property : blockState.getStates().keySet()) { - if (properties.get(property.getName()) != null) { - String value = properties.getString(property.getName()); + var propertyName = propertiesTag.findTag(property.getName(), LinTagType.stringTag()); + if (propertyName != null) { + String value = propertyName.value(); try { blockState = getBlockStateWith(blockState, property, value); } catch (IllegalArgumentException e) { - throw new InvalidFormatException("Invalid block state for " + blockState - .getBlockType() - .id() + ", " + property.getName() + ": " + value); + throw new InvalidFormatException("Invalid block state for " + blockState.getBlockType().id() + ", " + property.getName() + ": " + value); } } } @@ -134,7 +140,7 @@ public class AnvilChunk13 implements Chunk { } // parse block states - long[] blockStatesSerialized = NbtUtils.getChildTag(sectionTag, "BlockStates", BinaryTagTypes.LONG_ARRAY).value(); + long[] blockStatesSerialized = sectionTag.getTag("BlockStates", LinTagType.longArrayTag()).value(); BlockState[] chunkSectionBlocks = new BlockState[16 * 16 * 16]; blocks[y] = chunkSectionBlocks; @@ -143,8 +149,7 @@ public class AnvilChunk13 implements Chunk { } } - protected void readBlockStates(BlockState[] palette, long[] blockStatesSerialized, BlockState[] chunkSectionBlocks) throws - InvalidFormatException { + protected void readBlockStates(BlockState[] palette, long[] blockStatesSerialized, BlockState[] chunkSectionBlocks) throws InvalidFormatException { int paletteBits = 4; while ((1 << paletteBits) < palette.length) { ++paletteBits; @@ -163,7 +168,7 @@ public class AnvilChunk13 implements Chunk { throw new InvalidFormatException("Too short block state table"); } currentSerializedValue = blockStatesSerialized[nextSerializedItem++]; - localBlockId |= (int) ((currentSerializedValue & ((1 << bitsNextLong) - 1)) << remainingBits); + localBlockId |= (int) (currentSerializedValue & ((1L << bitsNextLong) - 1)) << remainingBits; currentSerializedValue >>>= bitsNextLong; remainingBits = 64 - bitsNextLong; } else { @@ -185,27 +190,23 @@ public class AnvilChunk13 implements Chunk { /** * Used to load the tile entities. */ - private void populateTileEntities() throws DataException { - tileEntities = new HashMap<>(); - if (rootTag.get("TileEntities") == null) { - return; + private Map populateTileEntities() { + LinListTag tags = rootTag.findListTag( + "TileEntities", LinTagType.compoundTag() + ); + if (tags == null) { + return ImmutableMap.of(); } - ListBinaryTag tags = NbtUtils.getChildTag(rootTag, "TileEntities", BinaryTagTypes.LIST); - - for (BinaryTag tag : tags) { - if (!(tag instanceof CompoundBinaryTag)) { - throw new InvalidFormatException("CompoundTag expected in TileEntities"); - } - - CompoundBinaryTag t = (CompoundBinaryTag) tag; - - int x = ((IntBinaryTag) t.get("x")).value(); - int y = ((IntBinaryTag) t.get("y")).value(); - int z = ((IntBinaryTag) t.get("z")).value(); + var tileEntities = ImmutableMap.builderWithExpectedSize(tags.value().size()); + for (LinCompoundTag tag : tags.value()) { + int x = tag.getTag("x", LinTagType.intTag()).valueAsInt(); + int y = tag.getTag("y", LinTagType.intTag()).valueAsInt(); + int z = tag.getTag("z", LinTagType.intTag()).valueAsInt(); BlockVector3 vec = BlockVector3.at(x, y, z); - tileEntities.put(vec, t); + tileEntities.put(vec, tag); } + return tileEntities.build(); } /** @@ -215,26 +216,21 @@ public class AnvilChunk13 implements Chunk { * * @param position the position * @return the compound tag for that position, which may be null - * @throws DataException thrown if there is a data error */ @Nullable - private CompoundBinaryTag getBlockTileEntity(BlockVector3 position) throws DataException { + private LinCompoundTag getBlockTileEntity(BlockVector3 position) { if (tileEntities == null) { - populateTileEntities(); + this.tileEntities = populateTileEntities(); } - CompoundBinaryTag values = tileEntities.get(position); - - return values; + return tileEntities.get(position); } @Override public BaseBlock getBlock(BlockVector3 position) throws DataException { - //FAWE start - simplified - int x = position.x() & 15; + int x = position.x() - rootX * 16; int y = position.y(); - int z = position.z() & 15; - //FAWE end + int z = position.z() - rootZ * 16; int section = y >> 4; int yIndex = y & 0x0F; @@ -246,15 +242,10 @@ public class AnvilChunk13 implements Chunk { BlockState[] sectionBlocks = blocks[section]; BlockState state = sectionBlocks != null ? sectionBlocks[(yIndex << 8) | (z << 4) | x] : BlockTypes.AIR.getDefaultState(); - CompoundBinaryTag tileEntity = getBlockTileEntity(position); + LinCompoundTag tileEntity = getBlockTileEntity(position); - if (tileEntity != null) { - return state.toBaseBlock(tileEntity); - } - - return state.toBaseBlock(); - } - //FAWE start - biome and entity restore + return state.toBaseBlock(tileEntity); + } //FAWE start - biome and entity restore @Override public BiomeType getBiome(final BlockVector3 position) throws DataException { @@ -277,21 +268,20 @@ public class AnvilChunk13 implements Chunk { /** * Used to load the biomes. */ - private void populateEntities() throws DataException { + private void populateEntities() { entities = new ArrayList<>(); - if (rootTag.get("Entities") == null) { + LinListTag tags = rootTag.findListTag( + "Entities", LinTagType.compoundTag() + ); + if (tags == null) { return; } - ListBinaryTag tags = NbtUtils.getChildTag(rootTag, "Entities", BinaryTagTypes.LIST); - for (BinaryTag tag : tags) { - if (!(tag instanceof CompoundBinaryTag)) { - throw new InvalidFormatException("CompoundTag expected in Entities"); - } - - CompoundBinaryTag t = (CompoundBinaryTag) tag; - - entities.add(new BaseEntity(EntityTypes.get(t.getString("id")), LazyReference.computed(t))); + for (LinCompoundTag tag : tags.value()) { + entities.add(new BaseEntity( + EntityTypes.get(tag.getTag("id", LinTagType.stringTag()).value()), + LazyReference.computed(tag) + )); } } @@ -299,12 +289,13 @@ public class AnvilChunk13 implements Chunk { /** * Used to load the biomes. */ - private void populateBiomes() throws DataException { + private void populateBiomes() { biomes = new BiomeType[256]; - if (rootTag.get("Biomes") == null) { + LinIntArrayTag biomeTag = rootTag.findTag("Biomes", LinTagType.intArrayTag()); + if (biomeTag == null) { return; } - int[] stored = NbtUtils.getChildTag(rootTag, "Biomes", BinaryTagTypes.INT_ARRAY).value(); + int[] stored = biomeTag.value(); for (int i = 0; i < 256; i++) { biomes[i] = BiomeTypes.getLegacy(stored[i]); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk15.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk15.java index 60b9d9617..955a6e70a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk15.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk15.java @@ -19,14 +19,14 @@ package com.sk89q.worldedit.world.chunk; -import com.fastasyncworldedit.core.util.NbtUtils; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinTagType; /** * The chunk format for Minecraft 1.15 and newer @@ -38,7 +38,7 @@ public class AnvilChunk15 extends AnvilChunk13 { * * @param tag the tag to read * @throws DataException on a data error - * @deprecated Use {@link #AnvilChunk15(CompoundBinaryTag)} + * @deprecated Use {@link #AnvilChunk15(LinCompoundTag)} */ @Deprecated public AnvilChunk15(CompoundTag tag) throws DataException { @@ -51,7 +51,7 @@ public class AnvilChunk15 extends AnvilChunk13 { * @param tag the tag to read * @throws DataException on a data error */ - public AnvilChunk15(CompoundBinaryTag tag) throws DataException { + public AnvilChunk15(LinCompoundTag tag) throws DataException { super(tag); } @@ -68,10 +68,11 @@ public class AnvilChunk15 extends AnvilChunk13 { private void populateBiomes() throws DataException { biomes = new BiomeType[1024]; - if (rootTag.get("Biomes") == null) { + LinIntArrayTag biomeTag = rootTag.findTag("Biomes", LinTagType.intArrayTag()); + if (biomeTag == null) { return; } - int[] stored = NbtUtils.getChildTag(rootTag, "Biomes", BinaryTagTypes.INT_ARRAY).value(); + int[] stored = biomeTag.value(); for (int i = 0; i < 1024; i++) { biomes[i] = BiomeTypes.getLegacy(stored[i]); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk16.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk16.java index 92f7f6caf..ff4c89e65 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk16.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk16.java @@ -20,10 +20,10 @@ package com.sk89q.worldedit.world.chunk; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.storage.InvalidFormatException; +import org.enginehub.linbus.tree.LinCompoundTag; /** * The chunk format for Minecraft 1.16 and 1.17 @@ -35,7 +35,7 @@ public class AnvilChunk16 extends AnvilChunk15 { * * @param tag the tag to read * @throws DataException on a data error - * @deprecated Use {@link #AnvilChunk16(CompoundBinaryTag)} + * @deprecated Use {@link #AnvilChunk16(LinCompoundTag)} */ @Deprecated public AnvilChunk16(CompoundTag tag) throws DataException { @@ -48,7 +48,7 @@ public class AnvilChunk16 extends AnvilChunk15 { * @param tag the tag to read * @throws DataException on a data error */ - public AnvilChunk16(CompoundBinaryTag tag) throws DataException { + public AnvilChunk16(LinCompoundTag tag) throws DataException { super(tag); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk17.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk17.java index 3789f9a79..fbddb66f0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk17.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk17.java @@ -20,16 +20,12 @@ package com.sk89q.worldedit.world.chunk; import com.fastasyncworldedit.core.util.NbtUtils; +import com.google.common.collect.ImmutableMap; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; @@ -39,10 +35,15 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.storage.InvalidFormatException; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import javax.annotation.Nullable; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Supplier; @@ -52,11 +53,11 @@ import java.util.function.Supplier; */ public class AnvilChunk17 implements Chunk { - private final CompoundBinaryTag rootTag; - private final Supplier entityTagSupplier; + private final LinCompoundTag rootTag; + private final Supplier entityTagSupplier; private BiomeType[] biomes; private BlockState[][] blocks; - private Map tileEntities; + private Map tileEntities; private List entities; // initialise with default values private int minSectionPosition = 0; @@ -68,16 +69,16 @@ public class AnvilChunk17 implements Chunk { * * @param tag the tag to read * @throws DataException on a data error - * @deprecated Use {@link #AnvilChunk17(CompoundBinaryTag, Supplier)} + * @deprecated Use {@link #AnvilChunk17(LinCompoundTag, Supplier)} */ @Deprecated public AnvilChunk17(CompoundTag tag, Supplier entitiesTag) throws DataException { - this(tag.asBinaryTag(), () -> { + this(tag.toLinTag(), () -> { CompoundTag compoundTag = entitiesTag.get(); if (compoundTag == null) { return null; } - return compoundTag.asBinaryTag(); + return compoundTag.toLinTag(); }); } @@ -89,20 +90,21 @@ public class AnvilChunk17 implements Chunk { * {@link #getEntities()} is called * @throws DataException on a data error */ - public AnvilChunk17(CompoundBinaryTag tag, Supplier entityTag) throws DataException { + public AnvilChunk17(LinCompoundTag tag, Supplier entityTag) throws DataException { rootTag = tag; entityTagSupplier = entityTag; blocks = new BlockState[16][]; // initialise with default length - ListBinaryTag sections = rootTag.getList("Sections"); + LinListTag> sections = rootTag.getTag("Sections", LinTagType.listTag()); - for (BinaryTag rawSectionTag : sections) { - if (!(rawSectionTag instanceof CompoundBinaryTag sectionTag)) { + for (LinTag rawSectionTag : sections.value()) { + if (!(rawSectionTag instanceof LinCompoundTag sectionTag)) { continue; } - if (sectionTag.get("Y") == null || sectionTag.get("BlockStates") == null) { + var sectionYTag = sectionTag.findTag("Y", LinTagType.byteTag()); + if (sectionYTag == null) { continue; // Empty section. } @@ -110,30 +112,32 @@ public class AnvilChunk17 implements Chunk { updateSectionIndexRange(y); // parse palette - ListBinaryTag paletteEntries = sectionTag.getList("Palette", BinaryTagTypes.COMPOUND); - int paletteSize = paletteEntries.size(); + LinListTag paletteEntries = sectionTag.getListTag("Palette", LinTagType.compoundTag()); + int paletteSize = paletteEntries.value().size(); if (paletteSize == 0) { continue; } BlockState[] palette = new BlockState[paletteSize]; for (int paletteEntryId = 0; paletteEntryId < paletteSize; paletteEntryId++) { - CompoundBinaryTag paletteEntry = (CompoundBinaryTag) paletteEntries.get(paletteEntryId); - BlockType type = BlockTypes.get(paletteEntry.getString("Name")); + LinCompoundTag paletteEntry = (LinCompoundTag) paletteEntries.get(paletteEntryId); + BlockType type = BlockTypes.get(paletteEntry.getTag("Name", LinTagType.stringTag()).value()); if (type == null) { - throw new InvalidFormatException("Invalid block type: " + paletteEntry.getString("Name")); + throw new InvalidFormatException("Invalid block type: " + paletteEntry + .getTag("Name", LinTagType.stringTag()) + .value()); } BlockState blockState = type.getDefaultState(); - if (paletteEntry.get("Properties") != null) { - CompoundBinaryTag properties = NbtUtils.getChildTag(paletteEntry, "Properties", BinaryTagTypes.COMPOUND); + LinCompoundTag properties = paletteEntry.findTag("Properties", LinTagType.compoundTag()); + if (properties != null) { for (Property property : blockState.getStates().keySet()) { - if (properties.get(property.getName()) != null) { - String value = properties.getString(property.getName()); + LinStringTag stringTag = properties.findTag(property.getName(), LinTagType.stringTag()); + if (stringTag != null) { try { - blockState = getBlockStateWith(blockState, property, value); + blockState = getBlockStateWith(blockState, property, stringTag.value()); } catch (IllegalArgumentException e) { throw new InvalidFormatException("Invalid block state for " + blockState .getBlockType() - .id() + ", " + property.getName() + ": " + value); + .id() + ", " + property.getName() + ": " + stringTag.value()); } } } @@ -142,7 +146,7 @@ public class AnvilChunk17 implements Chunk { } // parse block states - long[] blockStatesSerialized = sectionTag.getLongArray("BlockStates"); + long[] blockStatesSerialized = sectionTag.getTag("BlockStates", LinTagType.longArrayTag()).value(); BlockState[] chunkSectionBlocks = new BlockState[4096]; blocks[y - minSectionPosition] = chunkSectionBlocks; @@ -191,27 +195,24 @@ public class AnvilChunk17 implements Chunk { /** * Used to load the tile entities. */ - private void populateTileEntities() throws DataException { - tileEntities = new HashMap<>(); - if (rootTag.get("TileEntities") == null) { + private void populateTileEntities() { + LinListTag tags = rootTag.findListTag( + "TileEntities", LinTagType.compoundTag() + ); + if (tags == null) { + tileEntities = ImmutableMap.of(); return; } - ListBinaryTag tags = rootTag.getList("TileEntities"); - - for (BinaryTag tag : tags) { - if (!(tag instanceof CompoundBinaryTag)) { - throw new InvalidFormatException("CompoundTag expected in TileEntities"); - } - - CompoundBinaryTag t = (CompoundBinaryTag) tag; - - int x = ((IntBinaryTag) t.get("x")).value(); - int y = ((IntBinaryTag) t.get("y")).value(); - int z = ((IntBinaryTag) t.get("z")).value(); + var tileEntitiesBuilder = ImmutableMap.builderWithExpectedSize(tags.value().size()); + for (LinCompoundTag tag : tags.value()) { + int x = tag.getTag("x", LinTagType.intTag()).valueAsInt(); + int y = tag.getTag("y", LinTagType.intTag()).valueAsInt(); + int z = tag.getTag("z", LinTagType.intTag()).valueAsInt(); BlockVector3 vec = BlockVector3.at(x, y, z); - tileEntities.put(vec, t); + tileEntities.put(vec, tag); } + tileEntities = tileEntitiesBuilder.build(); } /** @@ -224,7 +225,7 @@ public class AnvilChunk17 implements Chunk { * @throws DataException thrown if there is a data error */ @Nullable - private CompoundBinaryTag getBlockTileEntity(BlockVector3 position) throws DataException { + private LinCompoundTag getBlockTileEntity(BlockVector3 position) throws DataException { if (tileEntities == null) { populateTileEntities(); } @@ -248,7 +249,7 @@ public class AnvilChunk17 implements Chunk { BlockState[] sectionBlocks = blocks[section - minSectionPosition]; BlockState state = sectionBlocks != null ? sectionBlocks[(yIndex << 8) | (z << 4) | x] : BlockTypes.AIR.getDefaultState(); - CompoundBinaryTag tileEntity = getBlockTileEntity(position); + LinCompoundTag tileEntity = getBlockTileEntity(position); if (tileEntity != null) { return state.toBaseBlock(tileEntity); @@ -270,10 +271,11 @@ public class AnvilChunk17 implements Chunk { private void populateBiomes() throws DataException { biomes = new BiomeType[64 * blocks.length]; - if (rootTag.get("Biomes") == null) { + LinIntArrayTag biomeTag = rootTag.findTag("Biomes", LinTagType.intArrayTag()); + if (biomeTag == null) { return; } - int[] stored = rootTag.getIntArray("Biomes"); + int[] stored = biomeTag.value(); for (int i = 0; i < 1024; i++) { biomes[i] = BiomeTypes.getLegacy(stored[i]); } @@ -290,22 +292,21 @@ public class AnvilChunk17 implements Chunk { /** * Used to load the biomes. */ - private void populateEntities() throws DataException { + private void populateEntities() { entities = new ArrayList<>(); - CompoundBinaryTag entityTag; - if (entityTagSupplier == null || (entityTag = entityTagSupplier.get()) == null) { + LinListTag tags = rootTag.findListTag( + "Entities", LinTagType.compoundTag() + ); + if (tags == null) { return; } - ListBinaryTag tags = entityTag.getList("Entities"); - for (BinaryTag tag : tags) { - if (!(tag instanceof CompoundBinaryTag)) { - throw new InvalidFormatException("CompoundTag expected in Entities"); - } + for (LinCompoundTag tag : tags.value()) { - CompoundBinaryTag t = (CompoundBinaryTag) tag; - - entities.add(new BaseEntity(EntityTypes.get(t.getString("id")), LazyReference.computed(t))); + entities.add(new BaseEntity( + EntityTypes.get(tag.getTag("id", LinTagType.stringTag()).value()), + LazyReference.computed(tag) + )); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java index 1e36938c4..c5736bfd5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java @@ -19,134 +19,93 @@ package com.sk89q.worldedit.world.chunk; -import com.fastasyncworldedit.core.util.NbtUtils; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.LongArrayTag; +import com.sk89q.jnbt.NBTUtils; +import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; -import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; import com.sk89q.worldedit.world.DataException; -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.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.storage.InvalidFormatException; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import javax.annotation.Nullable; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Supplier; /** * The chunk format for Minecraft 1.18 and newer */ public class AnvilChunk18 implements Chunk { - //FAWE start - CBT - private final CompoundBinaryTag rootTag; - //FAWE end + private final CompoundTag rootTag; private final Int2ObjectOpenHashMap blocks; - //FAWE start - entity and biome restore - private final int sectionCount; - private final Supplier entityTagSupplier; - private Int2ObjectOpenHashMap biomes = null; - private List entities; - private Map tileEntities; - //FAWE end + private final int rootX; + private final int rootZ; + private Map>> tileEntities; /** * Construct the chunk with a compound tag. * * @param tag the tag to read * @throws DataException on a data error - * @deprecated Use {@link AnvilChunk18#AnvilChunk18(CompoundBinaryTag, Supplier)} */ - @Deprecated public AnvilChunk18(CompoundTag tag) throws DataException { - //FAWE start - CBT - this(tag.asBinaryTag(), () -> null); - } - - /** - * Construct the chunk with a compound tag. - * - * @param tag the tag to read - * @throws DataException on a data error - * @deprecated Use {@link AnvilChunk18#AnvilChunk18(CompoundBinaryTag, Supplier)} - * @since 2.1.0 - */ - @Deprecated - public AnvilChunk18(CompoundTag tag, Supplier entitiesTag) throws DataException { - //FAWE start - CBT - this(tag.asBinaryTag(), () -> { - CompoundTag compoundTag = entitiesTag.get(); - return compoundTag == null ? null : compoundTag.asBinaryTag(); - }); - } - - /** - * Construct the chunk with a compound tag. - * - * @param tag the tag to read - * @throws DataException on a data error - * @since 2.1.0 - */ - public AnvilChunk18(CompoundBinaryTag tag, Supplier entityTag) throws DataException { - //FAWE end rootTag = tag; - entityTagSupplier = entityTag; - //FAWE start - CBT - ListBinaryTag sections = rootTag.getList("sections"); - this.sectionCount = sections.size(); + rootX = NBTUtils.getChildTag(rootTag.getValue(), "xPos", IntTag.class).getValue(); + rootZ = NBTUtils.getChildTag(rootTag.getValue(), "zPos", IntTag.class).getValue(); + List sections = NBTUtils.getChildTag(rootTag.getValue(), "sections", ListTag.class).getValue(); blocks = new Int2ObjectOpenHashMap<>(sections.size()); - for (BinaryTag rawSectionTag : sections) { - if (!(rawSectionTag instanceof CompoundBinaryTag sectionTag)) { + for (Tag rawSectionTag : sections) { + if (!(rawSectionTag instanceof CompoundTag)) { continue; } - int y = NbtUtils.getInt(sectionTag, "Y"); // sometimes a byte, sometimes an int + CompoundTag sectionTag = (CompoundTag) rawSectionTag; + Object yValue = sectionTag.getValue().get("Y").getValue(); // sometimes a byte, sometimes an int + if (!(yValue instanceof Number)) { + throw new InvalidFormatException("Y is not numeric: " + yValue); + } + int y = ((Number) yValue).intValue(); - BinaryTag rawBlockStatesTag = sectionTag.get("block_states"); // null for sections outside of the world limits - if (rawBlockStatesTag instanceof CompoundBinaryTag blockStatesTag) { + Tag rawBlockStatesTag = sectionTag.getValue().get("block_states"); // null for sections outside of the world limits + if (rawBlockStatesTag instanceof CompoundTag) { + CompoundTag blockStatesTag = (CompoundTag) rawBlockStatesTag; // parse palette - ListBinaryTag paletteEntries = blockStatesTag.getList("palette"); + List paletteEntries = blockStatesTag.getList("palette", CompoundTag.class); int paletteSize = paletteEntries.size(); if (paletteSize == 0) { continue; } BlockState[] palette = new BlockState[paletteSize]; for (int paletteEntryId = 0; paletteEntryId < paletteSize; paletteEntryId++) { - CompoundBinaryTag paletteEntry = (CompoundBinaryTag) paletteEntries.get(paletteEntryId); + CompoundTag paletteEntry = paletteEntries.get(paletteEntryId); BlockType type = BlockTypes.get(paletteEntry.getString("Name")); if (type == null) { throw new InvalidFormatException("Invalid block type: " + paletteEntry.getString("Name")); } BlockState blockState = type.getDefaultState(); - BinaryTag propertiesTag = paletteEntry.get("Properties"); - if (propertiesTag instanceof CompoundBinaryTag properties) { + if (paletteEntry.containsKey("Properties")) { + CompoundTag properties = NBTUtils.getChildTag(paletteEntry.getValue(), "Properties", CompoundTag.class); for (Property property : blockState.getStates().keySet()) { - String value; - if (!(value = properties.getString(property.getName())).isEmpty()) { + if (properties.containsKey(property.getName())) { + String value = properties.getString(property.getName()); try { blockState = getBlockStateWith(blockState, property, value); } catch (IllegalArgumentException e) { - throw new InvalidFormatException("Invalid block state for " + blockState - .getBlockType() - .id() + ", " + property.getName() + ": " + value); + throw new InvalidFormatException("Invalid block state for " + blockState.getBlockType().getId() + ", " + property.getName() + ": " + value); } } } @@ -160,7 +119,7 @@ public class AnvilChunk18 implements Chunk { } // parse block states - long[] blockStatesSerialized = blockStatesTag.getLongArray("data"); + long[] blockStatesSerialized = NBTUtils.getChildTag(blockStatesTag.getValue(), "data", LongArrayTag.class).getValue(); BlockState[] chunkSectionBlocks = new BlockState[16 * 16 * 16]; blocks.put(y, chunkSectionBlocks); @@ -168,7 +127,6 @@ public class AnvilChunk18 implements Chunk { readBlockStates(palette, blockStatesSerialized, chunkSectionBlocks); } } - //FAWE end } protected void readBlockStates(BlockState[] palette, long[] blockStatesSerialized, BlockState[] chunkSectionBlocks) throws InvalidFormatException { @@ -190,24 +148,28 @@ public class AnvilChunk18 implements Chunk { * Used to load the tile entities. */ private void populateTileEntities() throws DataException { - //FAWE start - CBT tileEntities = new HashMap<>(); - if (!(rootTag.get("block_entities") instanceof ListBinaryTag tags)) { + if (!rootTag.getValue().containsKey("block_entities")) { return; } - for (BinaryTag tag : tags) { - if (!(tag instanceof CompoundBinaryTag t)) { + List tags = NBTUtils.getChildTag(rootTag.getValue(), + "block_entities", ListTag.class).getValue(); + + for (Tag tag : tags) { + if (!(tag instanceof CompoundTag)) { throw new InvalidFormatException("CompoundTag expected in block_entities"); } - int x = t.getInt("x"); - int y = t.getInt("y"); - int z = t.getInt("z"); + CompoundTag t = (CompoundTag) tag; + + Map> values = new HashMap<>(t.getValue()); + int x = ((IntTag) values.get("x")).getValue(); + int y = ((IntTag) values.get("y")).getValue(); + int z = ((IntTag) values.get("z")).getValue(); BlockVector3 vec = BlockVector3.at(x, y, z); - tileEntities.put(vec, t); + tileEntities.put(vec, values); } - //FAWE end } /** @@ -220,21 +182,24 @@ public class AnvilChunk18 implements Chunk { * @throws DataException thrown if there is a data error */ @Nullable - private CompoundBinaryTag getBlockTileEntity(BlockVector3 position) throws DataException { - //FAWE start - CBT + private CompoundTag getBlockTileEntity(BlockVector3 position) throws DataException { if (tileEntities == null) { populateTileEntities(); } - return tileEntities.get(position); - //FAWE end + Map> values = tileEntities.get(position); + if (values == null) { + return null; + } + + return new CompoundTag(values); } @Override public BaseBlock getBlock(BlockVector3 position) throws DataException { - int x = position.x() & 15; - int y = position.y(); - int z = position.z() & 15; + int x = position.getX() - rootX * 16; + int y = position.getY(); + int z = position.getZ() - rootZ * 16; int section = y >> 4; int yIndex = y & 0x0F; @@ -245,7 +210,7 @@ public class AnvilChunk18 implements Chunk { } BlockState state = sectionBlocks[sectionBlocks.length == 1 ? 0 : ((yIndex << 8) | (z << 4) | x)]; - CompoundBinaryTag tileEntity = getBlockTileEntity(position); + CompoundTag tileEntity = getBlockTileEntity(position); if (tileEntity != null) { return state.toBaseBlock(tileEntity); @@ -254,110 +219,4 @@ public class AnvilChunk18 implements Chunk { return state.toBaseBlock(); } - @Override - public BiomeType getBiome(final BlockVector3 position) throws DataException { - if (biomes == null) { - populateBiomes(); - } - int x = (position.x() & 15) >> 2; - int y = (position.y() & 15) >> 2; - int z = (position.z() & 15) >> 2; - int section = position.y() >> 4; - BiomeType[] sectionBiomes = biomes.get(section); - if (sectionBiomes.length == 1) { - return sectionBiomes[0]; - } - return biomes.get(section)[y << 4 | z << 2 | x]; - } - - private void populateBiomes() throws DataException { - biomes = new Int2ObjectOpenHashMap<>(sectionCount); - ListBinaryTag sections = rootTag.getList("sections"); - for (BinaryTag rawSectionTag : sections) { - if (!(rawSectionTag instanceof CompoundBinaryTag sectionTag)) { - continue; - } - - int y = NbtUtils.getInt(sectionTag, "Y"); // sometimes a byte, sometimes an int - - BinaryTag rawBlockStatesTag = sectionTag.get("biomes"); // null for sections outside of the world limits - if (rawBlockStatesTag instanceof CompoundBinaryTag biomeTypesTag) { - - // parse palette - ListBinaryTag paletteEntries = biomeTypesTag.getList("palette"); - int paletteSize = paletteEntries.size(); - if (paletteSize == 0) { - continue; - } - BiomeType[] palette = new BiomeType[paletteSize]; - for (int paletteEntryId = 0; paletteEntryId < paletteSize; paletteEntryId++) { - String paletteEntry = paletteEntries.getString(paletteEntryId); - BiomeType type = BiomeType.REGISTRY.get(paletteEntry); - if (type == null) { - throw new InvalidFormatException("Invalid biome type: " + paletteEntry); - } - palette[paletteEntryId] = type; - } - if (paletteSize == 1) { - // the same block everywhere - biomes.put(y, palette); - continue; - } - - // parse block states - long[] biomesSerialized = biomeTypesTag.getLongArray("data"); - if (biomesSerialized.length == 0) { - throw new InvalidFormatException("Biome data not present."); - } - - BiomeType[] chunkSectionBiomes = new BiomeType[64]; - biomes.put(y, chunkSectionBiomes); - - readBiomes(palette, biomesSerialized, chunkSectionBiomes); - } - } - } - - protected void readBiomes(BiomeType[] palette, long[] biomesSerialized, BiomeType[] chunkSectionBiomes) throws - InvalidFormatException { - PackedIntArrayReader reader = new PackedIntArrayReader(biomesSerialized, 64); - for (int biomePos = 0; biomePos < chunkSectionBiomes.length; biomePos++) { - int index = reader.get(biomePos); - if (index >= palette.length) { - throw new InvalidFormatException("Invalid biome table entry: " + index); - } - chunkSectionBiomes[biomePos] = palette[index]; - } - } - - @Override - public List getEntities() throws DataException { - if (entities == null) { - populateEntities(); - } - return entities; - } - - /** - * Used to load the biomes. - */ - private void populateEntities() throws DataException { - entities = new ArrayList<>(); - CompoundBinaryTag entityTag; - if (entityTagSupplier == null || (entityTag = entityTagSupplier.get()) == null) { - return; - } - ListBinaryTag tags = NbtUtils.getChildTag(entityTag, "Entities", BinaryTagTypes.LIST); - - for (BinaryTag tag : tags) { - if (!(tag instanceof CompoundBinaryTag t)) { - throw new InvalidFormatException("CompoundTag expected in Entities"); - } - - entities.add(new BaseEntity(EntityTypes.get(t.getString("id")), LazyReference.computed(t))); - } - - } - - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java index 7edb163e3..783045520 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java @@ -19,21 +19,19 @@ package com.sk89q.worldedit.world.chunk; -import com.fastasyncworldedit.core.util.NbtUtils; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; import com.sk89q.worldedit.world.storage.InvalidFormatException; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTagType; import java.util.HashMap; import java.util.Map; @@ -43,24 +41,24 @@ import java.util.Map; */ public class OldChunk implements Chunk { - private final CompoundBinaryTag rootTag; + private final LinCompoundTag rootTag; private final byte[] blocks; private final byte[] data; private final int rootX; private final int rootZ; - private Map tileEntities; + private Map tileEntities; /** * Construct the chunk with a compound tag. * * @param tag the tag * @throws DataException if there is an error getting the chunk data - * @deprecated Use {@link #OldChunk(CompoundBinaryTag)} + * @deprecated Use {@link #OldChunk(LinCompoundTag)} */ @Deprecated public OldChunk(CompoundTag tag) throws DataException { - this(tag.asBinaryTag()); + this(tag.toLinTag()); } /** @@ -69,13 +67,13 @@ public class OldChunk implements Chunk { * @param tag the tag * @throws DataException if there is an error getting the chunk data */ - public OldChunk(CompoundBinaryTag tag) throws DataException { + public OldChunk(LinCompoundTag tag) throws DataException { rootTag = tag; - blocks = NbtUtils.getChildTag(rootTag, "Blocks", BinaryTagTypes.BYTE_ARRAY).value(); - data = NbtUtils.getChildTag(rootTag, "Data", BinaryTagTypes.BYTE_ARRAY).value(); - rootX = NbtUtils.getChildTag(rootTag, "xPos", BinaryTagTypes.INT).value(); - rootZ = NbtUtils.getChildTag(rootTag, "zPos", BinaryTagTypes.INT).value(); + blocks = rootTag.getTag("Blocks", LinTagType.byteArrayTag()).value(); + data = rootTag.getTag("Data", LinTagType.byteArrayTag()).value(); + rootX = rootTag.getTag("xPos", LinTagType.intTag()).value(); + rootZ = rootTag.getTag("zPos", LinTagType.intTag()).value(); int size = 16 * 16 * 128; if (blocks.length != size) { @@ -95,43 +93,39 @@ public class OldChunk implements Chunk { * @throws DataException if there is an error getting the chunk data */ private void populateTileEntities() throws DataException { - ListBinaryTag tags = NbtUtils.getChildTag(rootTag, "TileEntities", BinaryTagTypes.LIST); + LinListTag tags = rootTag.getTag("TileEntities", LinTagType.listTag()) + .asTypeChecked(LinTagType.compoundTag()); tileEntities = new HashMap<>(); - for (BinaryTag tag : tags) { - if (!(tag instanceof CompoundBinaryTag)) { - throw new InvalidFormatException("CompoundTag expected in TileEntities"); - } - - CompoundBinaryTag t = (CompoundBinaryTag) tag; - + for (LinCompoundTag t : tags.value()) { int x = 0; int y = 0; int z = 0; - CompoundBinaryTag.Builder values = CompoundBinaryTag.builder(); + LinCompoundTag.Builder values = LinCompoundTag.builder(); - for (String key : t.keySet()) { - BinaryTag value = t.get(key); + for (String key : t.value().keySet()) { + var value = t.value().get(key); switch (key) { - case "x": - if (value instanceof IntBinaryTag) { - x = ((IntBinaryTag) value).value(); + case "x" -> { + if (value instanceof LinIntTag v) { + x = v.valueAsInt(); } - break; - case "y": - if (value instanceof IntBinaryTag) { - y = ((IntBinaryTag) value).value(); + } + case "y" -> { + if (value instanceof LinIntTag v) { + y = v.valueAsInt(); } - break; - case "z": - if (value instanceof IntBinaryTag) { - z = ((IntBinaryTag) value).value(); + } + case "z" -> { + if (value instanceof LinIntTag v) { + z = v.valueAsInt(); } - break; - default: - break; + } + default -> { + // Do nothing. + } } values.put(key, value); @@ -151,13 +145,12 @@ public class OldChunk implements Chunk { * @return a tag * @throws DataException if there is an error getting the chunk data */ - private CompoundBinaryTag getBlockTileEntity(BlockVector3 position) throws DataException { + private LinCompoundTag getBlockTileEntity(BlockVector3 position) throws DataException { if (tileEntities == null) { populateTileEntities(); } - CompoundBinaryTag values = tileEntities.get(position); - return values; + return tileEntities.get(position); } @Override @@ -197,13 +190,9 @@ public class OldChunk implements Chunk { return BlockTypes.AIR.getDefaultState().toBaseBlock(); } - CompoundBinaryTag tileEntity = getBlockTileEntity(position); + LinCompoundTag tileEntity = getBlockTileEntity(position); - if (tileEntity != null) { - return state.toBaseBlock(tileEntity); - } - - return state.toBaseBlock(); + return state.toBaseBlock(tileEntity); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java index 3e3201fb6..df506c67a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java @@ -28,12 +28,15 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.chunk.Chunk; import com.sk89q.worldedit.world.storage.ChunkStore; import com.sk89q.worldedit.world.storage.MissingChunkException; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTagType; import java.io.IOException; import java.util.ArrayList; @@ -197,14 +200,14 @@ public class SnapshotRestore { if (restoreEntities) { try { for (BaseEntity entity : chunk.getEntities()) { - CompoundBinaryTag tag = entity.getNbtReference().getValue(); - ListBinaryTag pos = tag.getList("Pos"); - ListBinaryTag rotation = tag.getList("Rotation"); - double x = pos.getDouble(0); - double y = pos.getDouble(1); - double z = pos.getDouble(2); - float yRot = rotation.getFloat(0); - float xRot = rotation.getFloat(1); + LinCompoundTag tag = entity.getNbtReference().getValue(); + LinListTag pos = tag.getListTag("Pos", LinTagType.doubleTag()); + LinListTag rotation = tag.getListTag("Rotation", LinTagType.floatTag()); + double x = pos.get(0).value(); + double y = pos.get(1).value(); + double z = pos.get(2).value(); + float yRot = rotation.get(0).value(); + float xRot = rotation.get(1).value(); Location location = new Location(editSession.getWorld(), x, y, z, yRot, xRot); BlockVector3 blockVector3 = BlockVector3.at(x, y, z); if (region.contains(blockVector3) && (editSession.getMask() == null diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotRestore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotRestore.java index 5f9880fc0..39d4fb07b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotRestore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotRestore.java @@ -27,13 +27,15 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.chunk.Chunk; import com.sk89q.worldedit.world.storage.ChunkStore; import com.sk89q.worldedit.world.storage.MissingChunkException; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTagType; import java.io.IOException; import java.util.ArrayList; @@ -193,14 +195,14 @@ public class SnapshotRestore { if (restoreEntities) { try { for (BaseEntity entity : chunk.getEntities()) { - CompoundBinaryTag tag = entity.getNbtReference().getValue(); - ListBinaryTag pos = tag.getList("Pos", BinaryTagTypes.LIST); - ListBinaryTag rotation = tag.getList("Rotation", BinaryTagTypes.LIST); - double x = pos.getDouble(0); - double y = pos.getDouble(1); - double z = pos.getDouble(2); - float yRot = rotation.getFloat(0); - float xRot = rotation.getFloat(1); + LinCompoundTag tag = entity.getNbtReference().getValue(); + LinListTag pos = tag.getListTag("Pos", LinTagType.doubleTag()); + LinListTag rotation = tag.getListTag("Rotation", LinTagType.floatTag()); + double x = pos.get(0).value(); + double y = pos.get(1).value(); + double z = pos.get(2).value(); + float yRot = rotation.get(0).value(); + float xRot = rotation.get(1).value(); Location location = new Location(editSession.getWorld(), x, y, z, yRot, xRot); editSession.createEntity(location, entity); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreHelper.java index 58692732f..c8788a9ce 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreHelper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreHelper.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.world.storage; -import com.sk89q.jnbt.AdventureNBTConverter; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.Tag; @@ -54,7 +53,7 @@ public class ChunkStoreHelper { public static CompoundTag readCompoundTag(ChunkDataInputSupplier input) throws DataException, IOException { try (InputStream stream = input.openInputStream(); - NBTInputStream nbt = new NBTInputStream(stream)) { + NBTInputStream nbt = new NBTInputStream(stream)) { Tag tag = nbt.readNamedTag().getTag(); if (!(tag instanceof CompoundTag)) { throw new ChunkStoreException("CompoundTag expected for chunk; got " @@ -99,23 +98,20 @@ public class ChunkStoreHelper { if ((dataVersion > 0 || hasLevelSections(rootTag)) && dataVersion < currentDataVersion) { // only fix up MCA format, DFU doesn't support MCR chunks final DataFixer dataFixer = platform.getDataFixer(); if (dataFixer != null) { - //FAWE start - CBT - rootTag = (CompoundTag) AdventureNBTConverter.fromAdventure(dataFixer.fixUp(DataFixer.FixTypes.CHUNK, - rootTag.asBinaryTag(), dataVersion)); - //FAWE end + rootTag = new CompoundTag(dataFixer.fixUp(DataFixer.FixTypes.CHUNK, rootTag.toLinTag(), dataVersion)); dataVersion = currentDataVersion; } } if (dataVersion >= Constants.DATA_VERSION_MC_1_18) { - return new AnvilChunk18(rootTag, entitiesTag); + return new AnvilChunk18(rootTag); } - Map children = rootTag.getValue(); + Map> children = rootTag.getValue(); CompoundTag tag = null; // Find Level tag - for (Map.Entry entry : children.entrySet()) { + for (Map.Entry> entry : children.entrySet()) { if (entry.getKey().equals("Level")) { if (entry.getValue() instanceof CompoundTag) { tag = (CompoundTag) entry.getValue(); @@ -150,7 +146,7 @@ public class ChunkStoreHelper { return new AnvilChunk13(tag); } - Map tags = tag.getValue(); + Map> tags = tag.getValue(); if (tags.containsKey("Sections")) { return new AnvilChunk(tag); } @@ -159,8 +155,8 @@ public class ChunkStoreHelper { } private static boolean hasLevelSections(CompoundTag rootTag) { - Map children = rootTag.getValue(); - Tag levelTag = children.get("Level"); + Map> children = rootTag.getValue(); + Tag levelTag = children.get("Level"); if (levelTag instanceof CompoundTag) { return ((CompoundTag) levelTag).getValue().containsKey("Sections"); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java index 8d82026ff..90d552c10 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java @@ -22,6 +22,9 @@ package com.sk89q.worldedit.world.storage; import com.sk89q.jnbt.ListTag; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.util.Location; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinListTag; import static com.google.common.base.Preconditions.checkNotNull; @@ -44,15 +47,41 @@ public final class NBTConversions { * @param positionTag the position tag * @param directionTag the direction tag * @return a location + * @deprecated Use {@link #toLocation(Extent, LinListTag, LinListTag)} instead. */ + @Deprecated public static Location toLocation(Extent extent, ListTag positionTag, ListTag directionTag) { checkNotNull(extent); checkNotNull(positionTag); checkNotNull(directionTag); return new Location( - extent, - positionTag.asDouble(0), positionTag.asDouble(1), positionTag.asDouble(2), - directionTag.getFloat(0), directionTag.getFloat(1) + extent, + positionTag.asDouble(0), positionTag.asDouble(1), positionTag.asDouble(2), + directionTag.getFloat(0), directionTag.getFloat(1)); + } + + /** + * Read a {@code Location} from two list tags, the first of which contains + * three numbers for the X, Y, and Z components, and the second of + * which contains two numbers, the yaw and pitch in degrees. + * + *

    For values that are unavailable, their values will be 0.

    + * + * @param extent the extent + * @param positionTag the position tag + * @param rotationTag the rotation tag + * @return a location + */ + public static Location toLocation(Extent extent, LinListTag positionTag, LinListTag rotationTag) { + int posTagSize = positionTag.value().size(); + int rotTagSize = rotationTag.value().size(); + return new Location( + extent, + posTagSize > 0 ? positionTag.get(0).valueAsDouble() : 0, + posTagSize > 1 ? positionTag.get(1).valueAsDouble() : 0, + posTagSize > 2 ? positionTag.get(2).valueAsDouble() : 0, + rotTagSize > 0 ? rotationTag.get(0).valueAsFloat() : 0, + rotTagSize > 1 ? rotationTag.get(1).valueAsFloat() : 0 ); } diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/NBTConverter.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/NBTConverter.java index cd3c5c313..0d87917d9 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/NBTConverter.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/NBTConverter.java @@ -126,7 +126,7 @@ public final class NBTConverter { 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()) { + for (Entry> child : tag.getValue().entrySet()) { compound.put(child.getKey(), toNative(child.getValue())); } return compound; @@ -230,7 +230,7 @@ public final class NBTConverter { public static CompoundTag fromNative(net.minecraft.nbt.CompoundTag other) { Set tags = other.getKeys(); - Map map = new HashMap<>(); + Map> map = new HashMap<>(); for (String tagName : tags) { map.put(tagName, fromNative(other.getTag(tagName))); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/internal/NBTConverter.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/internal/NBTConverter.java index 9c10a6d30..82ab9ae23 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/internal/NBTConverter.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/internal/NBTConverter.java @@ -139,7 +139,7 @@ public final class NBTConverter { public static CompoundNBT toNative(CompoundTag tag) { CompoundNBT compound = new CompoundNBT(); - for (Entry child : tag.getValue().entrySet()) { + for (Entry> child : tag.getValue().entrySet()) { compound.put(child.getKey(), toNative(child.getValue())); } return compound; @@ -243,7 +243,7 @@ public final class NBTConverter { public static CompoundTag fromNative(CompoundNBT other) { Set tags = other.keySet(); - Map map = new HashMap<>(); + Map> map = new HashMap<>(); for (String tagName : tags) { map.put(tagName, fromNative(other.get(tagName))); } diff --git a/worldedit-libs/core/build.gradle.kts b/worldedit-libs/core/build.gradle.kts index c5eb10887..cace30cd0 100644 --- a/worldedit-libs/core/build.gradle.kts +++ b/worldedit-libs/core/build.gradle.kts @@ -12,5 +12,10 @@ dependencies { "shade"(libs.piston) "shade"(libs.pistonRuntime) "shade"(libs.pistonImpl) - "shade"(libs.adventureNbt) + // Linbus + "shade"(platform(libs.linBus.bom)) + "shade"(libs.linBus.common) + "shade"(libs.linBus.stream) + "shade"(libs.linBus.tree) + "shade"(libs.linBus.format.snbt) } From fee9029bf0e90094dc5453e91add495251d4c16c Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 27 Jun 2024 15:15:14 +0200 Subject: [PATCH 297/466] Add a BiomeCategories API (#2338) (#2777) * Add a BiomeCategories API (#2338) * Add a BiomeCategories API * licenses * Use a supplier to retain the lazy-load & dynamicness of the existing system, but still retaining the inversion of control that this PR was intended to provide * Minor fawe adapter cleanup * Actually add the new files? * Fixes --------- Co-authored-by: Maddy Miller --- .../ext/fawe/v1_19_R3/PaperweightAdapter.java | 40 ++ .../PaperweightWorldNativeAccess.java | 6 + .../PaperweightFaweWorldNativeAccess.java | 6 + .../ext/fawe/v1_20_R1/PaperweightAdapter.java | 57 ++- .../PaperweightWorldNativeAccess.java | 6 + .../PaperweightFaweWorldNativeAccess.java | 6 + .../ext/fawe/v1_20_R2/PaperweightAdapter.java | 258 ++++++++---- .../fawe/v1_20_R2/PaperweightFakePlayer.java | 2 +- .../PaperweightWorldNativeAccess.java | 23 +- .../PaperweightFaweWorldNativeAccess.java | 6 + .../ext.fawe/v1_20_R3/PaperweightAdapter.java | 253 ++++++++---- .../v1_20_R3/PaperweightFakePlayer.java | 2 +- .../PaperweightWorldNativeAccess.java | 15 +- .../PaperweightFaweWorldNativeAccess.java | 6 + .../ext.fawe/v1_20_R4/PaperweightAdapter.java | 368 ++++++++++-------- .../v1_20_R4/PaperweightFakePlayer.java | 2 +- .../PaperweightWorldNativeAccess.java | 27 +- .../PaperweightFaweWorldNativeAccess.java | 6 + .../adapter/IDelegateBukkitImplAdapter.java | 21 + .../bukkit/adapter/BukkitImplAdapter.java | 43 +- .../clipboard/io/FastSchematicReader.java | 4 - .../internal/wna/WorldNativeAccess.java | 4 +- .../sk89q/worldedit/registry/Category.java | 24 +- .../world/biome/BiomeCategories.java | 112 ++++++ .../worldedit/world/biome/BiomeCategory.java | 49 +++ 25 files changed, 975 insertions(+), 371 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeCategories.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeCategory.java diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java index a5c3da0e1..5b696c8f6 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java @@ -57,6 +57,7 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.io.file.SafeFiles; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.RegenOptions; +import com.sk89q.worldedit.world.biome.BiomeCategory; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BaseBlock; @@ -67,6 +68,9 @@ import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.item.ItemType; import net.minecraft.Util; import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; @@ -292,6 +296,14 @@ public final class PaperweightAdapter implements BukkitImplAdapter biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); + biomeRegistry.getTagNames().forEach(tagKey -> { + String key = tagKey.location().toString(); + if (BiomeCategory.REGISTRY.get(key) == null) { + BiomeCategory.REGISTRY.register(key, new BiomeCategory( + key, + () -> biomeRegistry.getTag(tagKey) + .stream() + .flatMap(HolderSet.Named::stream) + .map(Holder::value) + .map(this::adapt) + .collect(Collectors.toSet())) + ); + } + }); + } + // ------------------------------------------------------------------------ // Code that is less likely to break // ------------------------------------------------------------------------ diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightWorldNativeAccess.java index 7923c9e69..424422ce6 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightWorldNativeAccess.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightWorldNativeAccess.java @@ -154,6 +154,12 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess (net.minecraft.nbt.CompoundTag) fromNative(nbtData) - )); - }*/ - @Override public void sendFakeOP(Player player) { ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( @@ -858,7 +873,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); + biomeRegistry.getTagNames().forEach(tagKey -> { + String key = tagKey.location().toString(); + if (BiomeCategory.REGISTRY.get(key) == null) { + BiomeCategory.REGISTRY.register(key, new BiomeCategory( + key, + () -> biomeRegistry.getTag(tagKey) + .stream() + .flatMap(HolderSet.Named::stream) + .map(Holder::value) + .map(this::adapt) + .collect(Collectors.toSet())) + ); + } + }); + } // ------------------------------------------------------------------------ // Code that is less likely to break // ------------------------------------------------------------------------ diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightWorldNativeAccess.java index c7f3d3f3c..ffca9e50d 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightWorldNativeAccess.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightWorldNativeAccess.java @@ -154,6 +154,12 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess> 4, z >> 4); final BlockPos blockPos = new BlockPos(x, y, z); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - int internalId = Block.getId(blockData); - BlockState state = BlockStateIdAccess.getBlockStateById(internalId); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - - return state; + return adapt(blockData); } @Override @@ -357,8 +381,40 @@ public final class PaperweightAdapter implements BukkitImplAdapter, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle())); + public BiomeType getBiome(Location location) { + checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + + return biomeTypeFromNMSCache.computeIfAbsent(chunk.getNoiseBiome(x >> 2, y >> 2, z >> 2), b -> BiomeType.REGISTRY.get(b.unwrapKey().get().location().toString())); + } + + @Override + public void setBiome(Location location, BiomeType biome) { + checkNotNull(location); + checkNotNull(biome); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + chunk.setBiome(x >> 2, y >> 2, z >> 2, biomeTypeToNMSCache.computeIfAbsent(biome, b -> ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(ResourceKey.create(Registries.BIOME, new ResourceLocation(b.id()))))); + chunk.setUnsaved(true); + } + + @Override + public WorldNativeAccess createWorldNativeAccess(World world) { + return new PaperweightWorldNativeAccess(this, + new WeakReference<>(((CraftWorld) world).getHandle())); } private static net.minecraft.core.Direction adapt(Direction face) { @@ -381,13 +437,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter stateContainer, - net.minecraft.world.level.block.state.BlockState newState, - Map, Object> states + StateDefinition stateContainer, + net.minecraft.world.level.block.state.BlockState newState, + Map, Object> states ) { for (Map.Entry, Object> state : states.entrySet()) { net.minecraft.world.level.block.state.properties.Property property = - stateContainer.getProperty(state.getKey().getName()); + 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) { @@ -396,16 +452,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter) property) - .getValue(enumName).orElseThrow(() -> - new IllegalStateException( - "Enum property " + property.getName() + " does not contain " + enumName - ) - ); + .getValue(enumName).orElseThrow(() -> + new IllegalStateException( + "Enum property " + property.getName() + " does not contain " + enumName + ) + ); } newState = newState.setValue( - (net.minecraft.world.level.block.state.properties.Property) property, - (Comparable) value + (net.minecraft.world.level.block.state.properties.Property) property, + (Comparable) value ); } return newState; @@ -502,10 +558,10 @@ public final class PaperweightAdapter implements BukkitImplAdapter) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); + (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).toList()); } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { return new EnumProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); + (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).toList()); } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); } else { @@ -520,7 +576,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter> properties = new TreeMap<>(); Block block = getBlockFromType(blockType); StateDefinition blockStateList = - block.getStateDefinition(); + block.getStateDefinition(); for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { Property property = PROPERTY_CACHE.getUnchecked(state); properties.put(property.getName(), property); @@ -542,15 +598,15 @@ public final class PaperweightAdapter implements BukkitImplAdapter fakePlayers - = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); + = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); @Override public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) { @@ -583,7 +639,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter map = (Map) serverWorldsField.get(Bukkit.getServer()); + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); map.remove("faweregentempworld"); } catch (IllegalAccessException ignored) { } @@ -712,7 +769,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter { // bail out early if a future fails if (chunkLoadings.stream().anyMatch(ftr -> - ftr.isDone() && Futures.getUnchecked(ftr) == null + ftr.isDone() && Futures.getUnchecked(ftr) == null )) { return false; } @@ -758,9 +815,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter>) - getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) - .thenApply(either -> either.left().orElse(null)) + ((CompletableFuture>) + getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) + .thenApply(either -> either.left().orElse(null)) ); } catch (IllegalAccessException | InvocationTargetException e) { throw new IllegalStateException("Couldn't load chunk for regen.", e); @@ -782,12 +839,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( - SideEffect.NEIGHBORS, - SideEffect.LIGHTING, - SideEffect.VALIDATION, - SideEffect.ENTITY_AI, - SideEffect.EVENTS, - SideEffect.UPDATE + SideEffect.NEIGHBORS, + SideEffect.LIGHTING, + SideEffect.VALIDATION, + SideEffect.ENTITY_AI, + SideEffect.EVENTS, + SideEffect.UPDATE ); @Override @@ -796,7 +853,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); + biomeRegistry.getTagNames().forEach(tagKey -> { + String key = tagKey.location().toString(); + if (BiomeCategory.REGISTRY.get(key) == null) { + BiomeCategory.REGISTRY.register(key, new BiomeCategory( + key, + () -> biomeRegistry.getTag(tagKey) + .stream() + .flatMap(HolderSet.Named::stream) + .map(Holder::value) + .map(this::adapt) + .collect(Collectors.toSet())) + ); + } + }); + } + + @Override + public void sendBiomeUpdates(World world, Iterable chunks) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + + List nativeChunks = chunks instanceof Collection chunkCollection ? Lists.newArrayListWithCapacity(chunkCollection.size()) : Lists.newArrayList(); + for (BlockVector2 chunk : chunks) { + nativeChunks.add(originalWorld.getChunk(chunk.x(), chunk.z(), ChunkStatus.BIOMES, false)); + } + originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks); + } + // ------------------------------------------------------------------------ // Code that is less likely to break // ------------------------------------------------------------------------ @@ -978,7 +1074,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter> 4, z >> 4); final BlockPos blockPos = new BlockPos(x, y, z); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - int internalId = Block.getId(blockData); - BlockState state = BlockStateIdAccess.getBlockStateById(internalId); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - - return state; + return adapt(blockData); } @Override @@ -357,7 +381,38 @@ public final class PaperweightAdapter implements BukkitImplAdapter, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + public BiomeType getBiome(Location location) { + checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + + return biomeTypeFromNMSCache.computeIfAbsent(chunk.getNoiseBiome(x >> 2, y >> 2, z >> 2), b -> BiomeType.REGISTRY.get(b.unwrapKey().get().location().toString())); + } + + @Override + public void setBiome(Location location, BiomeType biome) { + checkNotNull(location); + checkNotNull(biome); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + chunk.setBiome(x >> 2, y >> 2, z >> 2, biomeTypeToNMSCache.computeIfAbsent(biome, b -> ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(ResourceKey.create(Registries.BIOME, new ResourceLocation(b.id()))))); + chunk.setUnsaved(true); + } + + @Override + public WorldNativeAccess createWorldNativeAccess(World world) { return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle())); } @@ -381,13 +436,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter stateContainer, - net.minecraft.world.level.block.state.BlockState newState, - Map, Object> states + StateDefinition stateContainer, + net.minecraft.world.level.block.state.BlockState newState, + Map, Object> states ) { for (Map.Entry, Object> state : states.entrySet()) { net.minecraft.world.level.block.state.properties.Property property = - stateContainer.getProperty(state.getKey().getName()); + 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) { @@ -396,16 +451,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter) property) - .getValue(enumName).orElseThrow(() -> - new IllegalStateException( - "Enum property " + property.getName() + " does not contain " + enumName - ) - ); + .getValue(enumName).orElseThrow(() -> + new IllegalStateException( + "Enum property " + property.getName() + " does not contain " + enumName + ) + ); } newState = newState.setValue( - (net.minecraft.world.level.block.state.properties.Property) property, - (Comparable) value + (net.minecraft.world.level.block.state.properties.Property) property, + (Comparable) value ); } return newState; @@ -502,10 +557,10 @@ public final class PaperweightAdapter implements BukkitImplAdapter) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); + (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).toList()); } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { return new EnumProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); + (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).toList()); } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); } else { @@ -520,7 +575,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter> properties = new TreeMap<>(); Block block = getBlockFromType(blockType); StateDefinition blockStateList = - block.getStateDefinition(); + block.getStateDefinition(); for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { Property property = PROPERTY_CACHE.getUnchecked(state); properties.put(property.getName(), property); @@ -542,15 +597,15 @@ public final class PaperweightAdapter implements BukkitImplAdapter map = (Map) serverWorldsField.get(Bukkit.getServer()); + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); map.remove("faweregentempworld"); } catch (IllegalAccessException ignored) { } @@ -712,7 +768,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter { // bail out early if a future fails if (chunkLoadings.stream().anyMatch(ftr -> - ftr.isDone() && Futures.getUnchecked(ftr) == null + ftr.isDone() && Futures.getUnchecked(ftr) == null )) { return false; } @@ -758,9 +814,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter>) - getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) - .thenApply(either -> either.left().orElse(null)) + ((CompletableFuture>) + getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) + .thenApply(either -> either.left().orElse(null)) ); } catch (IllegalAccessException | InvocationTargetException e) { throw new IllegalStateException("Couldn't load chunk for regen.", e); @@ -782,12 +838,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( - SideEffect.NEIGHBORS, - SideEffect.LIGHTING, - SideEffect.VALIDATION, - SideEffect.ENTITY_AI, - SideEffect.EVENTS, - SideEffect.UPDATE + SideEffect.NEIGHBORS, + SideEffect.LIGHTING, + SideEffect.VALIDATION, + SideEffect.ENTITY_AI, + SideEffect.EVENTS, + SideEffect.UPDATE ); @Override @@ -796,7 +852,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); + biomeRegistry.getTagNames().forEach(tagKey -> { + String key = tagKey.location().toString(); + if (BiomeCategory.REGISTRY.get(key) == null) { + BiomeCategory.REGISTRY.register(key, new BiomeCategory( + key, + () -> biomeRegistry.getTag(tagKey) + .stream() + .flatMap(HolderSet.Named::stream) + .map(Holder::value) + .map(this::adapt) + .collect(Collectors.toSet())) + ); + } + }); + } + + @Override + public void sendBiomeUpdates(World world, Iterable chunks) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + + List nativeChunks = chunks instanceof Collection chunkCollection ? Lists.newArrayListWithCapacity(chunkCollection.size()) : Lists.newArrayList(); + for (BlockVector2 chunk : chunks) { + nativeChunks.add(originalWorld.getChunk(chunk.x(), chunk.z(), ChunkStatus.BIOMES, false)); + } + originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks); + } + // ------------------------------------------------------------------------ // Code that is less likely to break // ------------------------------------------------------------------------ @@ -978,7 +1073,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter> 4, z >> 4); final BlockPos blockPos = new BlockPos(x, y, z); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - int internalId = Block.getId(blockData); - BlockState state = BlockStateIdAccess.getBlockStateById(internalId); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - - return state; + return adapt(blockData); } @Override @@ -387,7 +389,38 @@ public final class PaperweightAdapter implements BukkitImplAdapter, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + public BiomeType getBiome(Location location) { + checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + + return biomeTypeFromNMSCache.computeIfAbsent(chunk.getNoiseBiome(x >> 2, y >> 2, z >> 2), b -> BiomeType.REGISTRY.get(b.unwrapKey().get().location().toString())); + } + + @Override + public void setBiome(Location location, BiomeType biome) { + checkNotNull(location); + checkNotNull(biome); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + chunk.setBiome(x >> 2, y >> 2, z >> 2, biomeTypeToNMSCache.computeIfAbsent(biome, b -> ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(ResourceKey.create(Registries.BIOME, new ResourceLocation(b.id()))))); + chunk.setUnsaved(true); + } + + @Override + public WorldNativeAccess createWorldNativeAccess(World world) { return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle())); } @@ -411,13 +444,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter stateContainer, - net.minecraft.world.level.block.state.BlockState newState, - Map, Object> states + StateDefinition stateContainer, + net.minecraft.world.level.block.state.BlockState newState, + Map, Object> states ) { for (Map.Entry, Object> state : states.entrySet()) { net.minecraft.world.level.block.state.properties.Property property = - stateContainer.getProperty(state.getKey().getName()); + 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) { @@ -426,16 +459,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter) property) - .getValue(enumName).orElseThrow(() -> - new IllegalStateException( - "Enum property " + property.getName() + " does not contain " + enumName - ) - ); + .getValue(enumName).orElseThrow(() -> + new IllegalStateException( + "Enum property " + property.getName() + " does not contain " + enumName + ) + ); } newState = newState.setValue( - (net.minecraft.world.level.block.state.properties.Property) property, - (Comparable) value + (net.minecraft.world.level.block.state.properties.Property) property, + (Comparable) value ); } return newState; @@ -486,7 +519,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter> PROPERTY_CACHE = CacheBuilder - .newBuilder() - .build(new CacheLoader>() { - @Override - public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else if (state instanceof DirectionProperty) { - return new DirectionalProperty( - state.getName(), - (List) state - .getPossibleValues() - .stream() - .map(e -> Direction.valueOf(((StringRepresentable) e) - .getSerializedName() - .toUpperCase(Locale.ROOT))) - .collect(Collectors.toList()) - ); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - return new EnumProperty( - state.getName(), - (List) state - .getPossibleValues() - .stream() - .map(e -> ((StringRepresentable) e).getSerializedName()) - .collect(Collectors.toList()) - ); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else { - throw new IllegalArgumentException("WorldEdit needs an update to support " + state - .getClass() - .getSimpleName()); - } - } - }); + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static final LoadingCache> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { + @Override + public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { + if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else if (state instanceof DirectionProperty) { + return new DirectionalProperty(state.getName(), + (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).toList()); + } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + return new EnumProperty(state.getName(), + (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).toList()); + } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else { + throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); + } + } + }); - @SuppressWarnings({"rawtypes"}) + @SuppressWarnings({ "rawtypes" }) @Override public Map> getProperties(BlockType blockType) { Map> properties = new TreeMap<>(); Block block = getBlockFromType(blockType); StateDefinition blockStateList = - block.getStateDefinition(); + block.getStateDefinition(); for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { Property property = PROPERTY_CACHE.getUnchecked(state); properties.put(property.getName(), property); @@ -579,8 +594,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter fakePlayers - = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); + = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); @Override - public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) { + public boolean simulateItemUse(World world, BlockVector3 position, BaseItem item, Direction face) { CraftWorld craftWorld = (CraftWorld) world; ServerLevel worldServer = craftWorld.getHandle(); ItemStack stack = CraftItemStack.asNMSCopy(adapt( - item instanceof BaseItemStack - ? ((BaseItemStack) item) - : new BaseItemStack(item.getType(), item.getNbtReference(), 1) + item instanceof BaseItemStack + ? ((BaseItemStack) item) + : new BaseItemStack(item.getType(), item.getNbtReference(), 1) )); PaperweightFakePlayer fakePlayer; @@ -647,8 +662,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter map = (Map) serverWorldsField.get(Bukkit.getServer()); + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); map.remove("faweregentempworld"); } catch (IllegalAccessException ignored) { } @@ -777,8 +781,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter> chunkLoadings = submitChunkLoadTasks(region, serverWorld); BlockableEventLoop executor; try { @@ -789,7 +792,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter { // bail out early if a future fails if (chunkLoadings.stream().anyMatch(ftr -> - ftr.isDone() && Futures.getUnchecked(ftr) == null + ftr.isDone() && Futures.getUnchecked(ftr) == null )) { return false; } @@ -835,9 +838,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter>) - getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) - .thenApply(either -> either.orElse(null)) + ((CompletableFuture>) + getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) + .thenApply(either -> either.orElse(null)) ); } catch (IllegalAccessException | InvocationTargetException e) { throw new IllegalStateException("Couldn't load chunk for regen.", e); @@ -859,12 +862,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( - SideEffect.NEIGHBORS, - SideEffect.LIGHTING, - SideEffect.VALIDATION, - SideEffect.ENTITY_AI, - SideEffect.EVENTS, - SideEffect.UPDATE + SideEffect.NEIGHBORS, + SideEffect.LIGHTING, + SideEffect.VALIDATION, + SideEffect.ENTITY_AI, + SideEffect.EVENTS, + SideEffect.UPDATE ); @Override @@ -873,7 +876,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); + biomeRegistry.getTagNames().forEach(tagKey -> { + String key = tagKey.location().toString(); + if (BiomeCategory.REGISTRY.get(key) == null) { + BiomeCategory.REGISTRY.register(key, new BiomeCategory( + key, + () -> biomeRegistry.getTag(tagKey) + .stream() + .flatMap(HolderSet.Named::stream) + .map(Holder::value) + .map(this::adapt) + .collect(Collectors.toSet())) + ); + } + }); + } + + @Override + public void sendBiomeUpdates(World world, Iterable chunks) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + + List nativeChunks = chunks instanceof Collection chunkCollection ? Lists.newArrayListWithCapacity(chunkCollection.size()) : Lists.newArrayList(); + for (BlockVector2 chunk : chunks) { + nativeChunks.add(originalWorld.getChunk(chunk.x(), chunk.z(), ChunkStatus.BIOMES, false)); + } + originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks); + } + // ------------------------------------------------------------------------ // Code that is less likely to break // ------------------------------------------------------------------------ @@ -1022,7 +1064,6 @@ public final class PaperweightAdapter implements BukkitImplAdapter extends BukkitImplAdapter { return getParent().getInternalBlockStateId(state); } + @Override + default boolean clearContainerBlockContents(World world, BlockVector3 pt) { + return getParent().clearContainerBlockContents(world, pt); + } + + @Override + default void setBiome(Location location, BiomeType biome) { + getParent().setBiome(location, biome); + } + + @Override + default BiomeType getBiome(Location location) { + return getParent().getBiome(location); + } + + @Override + default void sendBiomeUpdates(World world, Iterable chunks) { + getParent().sendBiomeUpdates(world, chunks); + } + @Override default BlockMaterial getMaterial(BlockType blockType) { return getParent().getMaterial(blockType); diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java index d656e874a..8fee3b417 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java @@ -35,6 +35,7 @@ import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.registry.state.Property; @@ -110,7 +111,7 @@ public interface BukkitImplAdapter extends IBukkitAdapter { BlockState getBlock(Location location); /** - * Get the block at the given location. + * Get the block with NBT data at the given location. * * @param location the location * @return the block @@ -280,6 +281,46 @@ public interface BukkitImplAdapter extends IBukkitAdapter { throw new UnsupportedOperationException("This adapter does not support clearing block contents."); } + /** + * Set the biome at a location. + * + * @param location the location + * @param biome the new biome + */ + default void setBiome(Location location, BiomeType biome) { + throw new UnsupportedOperationException("This adapter does not support custom biomes."); + } + + /** + * Gets the current biome at a location. + * + * @param location the location + * @return the biome + */ + default BiomeType getBiome(Location location) { + throw new UnsupportedOperationException("This adapter does not support custom biomes."); + } + + /** + * Initialize registries that require NMS access. + */ + default void initializeRegistries() { + + } + + /** + * Sends biome updates for the given chunks. + * + *

    This doesn't modify biomes at all, it just sends the current state of the biomes + * in the world to all of the nearby players, updating the visual representation of the + * biomes on their clients.

    + * + * @param world the world + * @param chunks a list of chunk coordinates to send biome updates for + */ + default void sendBiomeUpdates(World world, Iterable chunks) { + } + //FAWE start default BlockMaterial getMaterial(BlockType blockType) { return getMaterial(blockType.getDefaultState()); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java index b32d42c04..71d139789 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java @@ -109,26 +109,22 @@ public class FastSchematicReader extends NBTSchematicReader { if (fixer == null || dataVersion == -1) { return tag; } - //FAWE start - LinTag return (CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp( DataFixer.FixTypes.BLOCK_ENTITY, tag.toLinTag(), dataVersion )); - //FAWE end } private CompoundTag fixEntity(CompoundTag tag) { if (fixer == null || dataVersion == -1) { return tag; } - //FAWE start - LinTag return (CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp( DataFixer.FixTypes.ENTITY, tag.toLinTag(), dataVersion )); - //FAWE end } private String fixBiome(String biomePalettePart) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java index 56cab805f..097db6964 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java @@ -146,7 +146,9 @@ public interface WorldNativeAccess { void markBlockChanged(NC chunk, NP position); - void notifyNeighbors(NP pos, NBS oldState, NBS newState); + void notifyNeighbors(NP pos, NBS oldState, NBS newState);; + + void updateBlock(NP pos, NBS oldState, NBS newState); void updateNeighbors(NP pos, NBS oldState, NBS newState, int recursionLimit); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Category.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Category.java index 92a859652..e18499c04 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Category.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Category.java @@ -23,17 +23,25 @@ import com.fastasyncworldedit.core.registry.RegistryItem; import java.util.HashSet; import java.util.Set; +import java.util.function.Supplier; //FAWE start - implements RegistryItem public abstract class Category implements RegistryItem, Keyed { //FAWE end private final Set set = new HashSet<>(); + private final Supplier> supplier; protected final String id; private boolean empty = true; - protected Category(final String id) { + public Category(final String id) { this.id = id; + this.supplier = null; + } + + public Category(String id, Supplier> contentSupplier) { + this.id = id; + this.supplier = contentSupplier; } @Override @@ -43,7 +51,11 @@ public abstract class Category implements RegistryItem, Keyed { public final Set getAll() { if (this.empty) { - this.set.addAll(this.load()); + if (supplier != null) { + this.set.addAll(this.supplier.get()); + } else { + this.set.addAll(this.load()); + } this.empty = false; } return this.set; @@ -62,6 +74,14 @@ public abstract class Category implements RegistryItem, Keyed { return internalId; } + /** + * Loads the contents of this category from the platform. + * + * @return The loaded contents of the category + * @deprecated The load system will be removed in a future WorldEdit release. The registries should be populated by + * the platforms via the supplier constructor. + */ + @Deprecated protected abstract Set load(); //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeCategories.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeCategories.java new file mode 100644 index 000000000..ee1cca1c0 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeCategories.java @@ -0,0 +1,112 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.world.biome; + +/** + * Stores a list of common {@link BiomeCategory BiomeCategories}. + * + * @see BiomeCategory + */ +@SuppressWarnings("unused") +public final class BiomeCategories { + public static final BiomeCategory ALLOWS_SURFACE_SLIME_SPAWNS = get("minecraft:allows_surface_slime_spawns"); + public static final BiomeCategory ALLOWS_TROPICAL_FISH_SPAWNS_AT_ANY_HEIGHT = get("minecraft:allows_tropical_fish_spawns_at_any_height"); + public static final BiomeCategory HAS_CLOSER_WATER_FOG = get("minecraft:has_closer_water_fog"); + public static final BiomeCategory HAS_STRUCTURE_ANCIENT_CITY = get("minecraft:has_structure/ancient_city"); + public static final BiomeCategory HAS_STRUCTURE_BASTION_REMNANT = get("minecraft:has_structure/bastion_remnant"); + public static final BiomeCategory HAS_STRUCTURE_BURIED_TREASURE = get("minecraft:has_structure/buried_treasure"); + public static final BiomeCategory HAS_STRUCTURE_DESERT_PYRAMID = get("minecraft:has_structure/desert_pyramid"); + public static final BiomeCategory HAS_STRUCTURE_END_CITY = get("minecraft:has_structure/end_city"); + public static final BiomeCategory HAS_STRUCTURE_IGLOO = get("minecraft:has_structure/igloo"); + public static final BiomeCategory HAS_STRUCTURE_JUNGLE_TEMPLE = get("minecraft:has_structure/jungle_temple"); + public static final BiomeCategory HAS_STRUCTURE_MINESHAFT = get("minecraft:has_structure/mineshaft"); + public static final BiomeCategory HAS_STRUCTURE_MINESHAFT_MESA = get("minecraft:has_structure/mineshaft_mesa"); + public static final BiomeCategory HAS_STRUCTURE_NETHER_FORTRESS = get("minecraft:has_structure/nether_fortress"); + public static final BiomeCategory HAS_STRUCTURE_NETHER_FOSSIL = get("minecraft:has_structure/nether_fossil"); + public static final BiomeCategory HAS_STRUCTURE_OCEAN_MONUMENT = get("minecraft:has_structure/ocean_monument"); + public static final BiomeCategory HAS_STRUCTURE_OCEAN_RUIN_COLD = get("minecraft:has_structure/ocean_ruin_cold"); + public static final BiomeCategory HAS_STRUCTURE_OCEAN_RUIN_WARM = get("minecraft:has_structure/ocean_ruin_warm"); + public static final BiomeCategory HAS_STRUCTURE_PILLAGER_OUTPOST = get("minecraft:has_structure/pillager_outpost"); + public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_DESERT = get("minecraft:has_structure/ruined_portal_desert"); + public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_JUNGLE = get("minecraft:has_structure/ruined_portal_jungle"); + public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_MOUNTAIN = get("minecraft:has_structure/ruined_portal_mountain"); + public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_NETHER = get("minecraft:has_structure/ruined_portal_nether"); + public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_OCEAN = get("minecraft:has_structure/ruined_portal_ocean"); + public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_STANDARD = get("minecraft:has_structure/ruined_portal_standard"); + public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_SWAMP = get("minecraft:has_structure/ruined_portal_swamp"); + public static final BiomeCategory HAS_STRUCTURE_SHIPWRECK = get("minecraft:has_structure/shipwreck"); + public static final BiomeCategory HAS_STRUCTURE_SHIPWRECK_BEACHED = get("minecraft:has_structure/shipwreck_beached"); + public static final BiomeCategory HAS_STRUCTURE_STRONGHOLD = get("minecraft:has_structure/stronghold"); + public static final BiomeCategory HAS_STRUCTURE_SWAMP_HUT = get("minecraft:has_structure/swamp_hut"); + public static final BiomeCategory HAS_STRUCTURE_TRAIL_RUINS = get("minecraft:has_structure/trail_ruins"); + public static final BiomeCategory HAS_STRUCTURE_VILLAGE_DESERT = get("minecraft:has_structure/village_desert"); + public static final BiomeCategory HAS_STRUCTURE_VILLAGE_PLAINS = get("minecraft:has_structure/village_plains"); + public static final BiomeCategory HAS_STRUCTURE_VILLAGE_SAVANNA = get("minecraft:has_structure/village_savanna"); + public static final BiomeCategory HAS_STRUCTURE_VILLAGE_SNOWY = get("minecraft:has_structure/village_snowy"); + public static final BiomeCategory HAS_STRUCTURE_VILLAGE_TAIGA = get("minecraft:has_structure/village_taiga"); + public static final BiomeCategory HAS_STRUCTURE_WOODLAND_MANSION = get("minecraft:has_structure/woodland_mansion"); + public static final BiomeCategory INCREASED_FIRE_BURNOUT = get("minecraft:increased_fire_burnout"); + public static final BiomeCategory IS_BADLANDS = get("minecraft:is_badlands"); + public static final BiomeCategory IS_BEACH = get("minecraft:is_beach"); + public static final BiomeCategory IS_DEEP_OCEAN = get("minecraft:is_deep_ocean"); + public static final BiomeCategory IS_END = get("minecraft:is_end"); + public static final BiomeCategory IS_FOREST = get("minecraft:is_forest"); + public static final BiomeCategory IS_HILL = get("minecraft:is_hill"); + public static final BiomeCategory IS_JUNGLE = get("minecraft:is_jungle"); + public static final BiomeCategory IS_MOUNTAIN = get("minecraft:is_mountain"); + public static final BiomeCategory IS_NETHER = get("minecraft:is_nether"); + public static final BiomeCategory IS_OCEAN = get("minecraft:is_ocean"); + public static final BiomeCategory IS_OVERWORLD = get("minecraft:is_overworld"); + public static final BiomeCategory IS_RIVER = get("minecraft:is_river"); + public static final BiomeCategory IS_SAVANNA = get("minecraft:is_savanna"); + public static final BiomeCategory IS_TAIGA = get("minecraft:is_taiga"); + public static final BiomeCategory MINESHAFT_BLOCKING = get("minecraft:mineshaft_blocking"); + public static final BiomeCategory MORE_FREQUENT_DROWNED_SPAWNS = get("minecraft:more_frequent_drowned_spawns"); + public static final BiomeCategory PLAYS_UNDERWATER_MUSIC = get("minecraft:plays_underwater_music"); + public static final BiomeCategory POLAR_BEARS_SPAWN_ON_ALTERNATE_BLOCKS = get("minecraft:polar_bears_spawn_on_alternate_blocks"); + public static final BiomeCategory PRODUCES_CORALS_FROM_BONEMEAL = get("minecraft:produces_corals_from_bonemeal"); + public static final BiomeCategory REDUCE_WATER_AMBIENT_SPAWNS = get("minecraft:reduce_water_ambient_spawns"); + public static final BiomeCategory REQUIRED_OCEAN_MONUMENT_SURROUNDING = get("minecraft:required_ocean_monument_surrounding"); + public static final BiomeCategory SNOW_GOLEM_MELTS = get("minecraft:snow_golem_melts"); + public static final BiomeCategory SPAWNS_COLD_VARIANT_FROGS = get("minecraft:spawns_cold_variant_frogs"); + public static final BiomeCategory SPAWNS_GOLD_RABBITS = get("minecraft:spawns_gold_rabbits"); + public static final BiomeCategory SPAWNS_SNOW_FOXES = get("minecraft:spawns_snow_foxes"); + public static final BiomeCategory SPAWNS_WARM_VARIANT_FROGS = get("minecraft:spawns_warm_variant_frogs"); + public static final BiomeCategory SPAWNS_WHITE_RABBITS = get("minecraft:spawns_white_rabbits"); + public static final BiomeCategory STRONGHOLD_BIASED_TO = get("minecraft:stronghold_biased_to"); + public static final BiomeCategory WATER_ON_MAP_OUTLINES = get("minecraft:water_on_map_outlines"); + public static final BiomeCategory WITHOUT_PATROL_SPAWNS = get("minecraft:without_patrol_spawns"); + public static final BiomeCategory WITHOUT_WANDERING_TRADER_SPAWNS = get("minecraft:without_wandering_trader_spawns"); + public static final BiomeCategory WITHOUT_ZOMBIE_SIEGES = get("minecraft:without_zombie_sieges"); + + private BiomeCategories() { + } + + /** + * Gets the {@link BiomeCategory} associated with the given id. + */ + public static BiomeCategory get(String id) { + BiomeCategory entry = BiomeCategory.REGISTRY.get(id); + if (entry == null) { + return new BiomeCategory(id); + } + return entry; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeCategory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeCategory.java new file mode 100644 index 000000000..a51a86823 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeCategory.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.world.biome; + +import com.sk89q.worldedit.registry.Category; +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.NamespacedRegistry; + +import java.util.Set; +import java.util.function.Supplier; + +/** + * A category of biomes. + */ +public class BiomeCategory extends Category implements Keyed { + + public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("biome tag", true); + + public BiomeCategory(final String id) { + super(id); + } + + public BiomeCategory(final String id, final Supplier> contentSupplier) { + super(id, contentSupplier); + } + + @Override + protected Set load() { + return Set.of(); + } + +} From 99a58f66cd95a1f4edffed60731f7f37b1b54d7d Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Thu, 27 Jun 2024 14:59:32 +0100 Subject: [PATCH 298/466] Fix property loading --- .../ext/fawe/v1_19_R3/PaperweightAdapter.java | 54 ++++++++++++------ .../ext/fawe/v1_20_R1/PaperweightAdapter.java | 54 ++++++++++++------ .../ext/fawe/v1_20_R2/PaperweightAdapter.java | 54 ++++++++++++------ .../ext.fawe/v1_20_R3/PaperweightAdapter.java | 54 ++++++++++++------ .../ext.fawe/v1_20_R4/PaperweightAdapter.java | 56 ++++++++++++------- 5 files changed, 181 insertions(+), 91 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java index 5b696c8f6..87135fa86 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java @@ -507,24 +507,42 @@ public final class PaperweightAdapter implements BukkitImplAdapter> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { - @Override - public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else if (state instanceof DirectionProperty) { - return new DirectionalProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - return new EnumProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else { - throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); - } - } - }); + private static final LoadingCache> PROPERTY_CACHE = CacheBuilder + .newBuilder() + .build(new CacheLoader<>() { + @Override + public Property load(net.minecraft.world.level.block.state.properties.Property state) { + if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else if (state instanceof DirectionProperty) { + return new DirectionalProperty( + state.getName(), + new ArrayList<>((List) state + .getPossibleValues() + .stream() + .map(e -> Direction.valueOf(((StringRepresentable) e) + .getSerializedName() + .toUpperCase(Locale.ROOT))) + .toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + return new EnumProperty( + state.getName(), + new ArrayList<>((List) state + .getPossibleValues() + .stream() + .map(e -> ((StringRepresentable) e).getSerializedName()) + .toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else { + throw new IllegalArgumentException("WorldEdit needs an update to support " + state + .getClass() + .getSimpleName()); + } + } + }); @SuppressWarnings({ "rawtypes" }) @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java index 233212aef..0cecbb45b 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java @@ -561,24 +561,42 @@ public final class PaperweightAdapter implements BukkitImplAdapter> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { - @Override - public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else if (state instanceof DirectionProperty) { - return new DirectionalProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - return new EnumProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else { - throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); - } - } - }); + private static final LoadingCache> PROPERTY_CACHE = CacheBuilder + .newBuilder() + .build(new CacheLoader<>() { + @Override + public Property load(net.minecraft.world.level.block.state.properties.Property state) { + if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else if (state instanceof DirectionProperty) { + return new DirectionalProperty( + state.getName(), + new ArrayList<>((List) state + .getPossibleValues() + .stream() + .map(e -> Direction.valueOf(((StringRepresentable) e) + .getSerializedName() + .toUpperCase(Locale.ROOT))) + .toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + return new EnumProperty( + state.getName(), + new ArrayList<>((List) state + .getPossibleValues() + .stream() + .map(e -> ((StringRepresentable) e).getSerializedName()) + .toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else { + throw new IllegalArgumentException("WorldEdit needs an update to support " + state + .getClass() + .getSimpleName()); + } + } + }); @SuppressWarnings({ "rawtypes" }) @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java index 19f9aa596..9aaeb7bc2 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java @@ -551,24 +551,42 @@ public final class PaperweightAdapter implements BukkitImplAdapter> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { - @Override - public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else if (state instanceof DirectionProperty) { - return new DirectionalProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).toList()); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - return new EnumProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).toList()); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else { - throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); - } - } - }); + private static final LoadingCache> PROPERTY_CACHE = CacheBuilder + .newBuilder() + .build(new CacheLoader<>() { + @Override + public Property load(net.minecraft.world.level.block.state.properties.Property state) { + if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else if (state instanceof DirectionProperty) { + return new DirectionalProperty( + state.getName(), + new ArrayList<>((List) state + .getPossibleValues() + .stream() + .map(e -> Direction.valueOf(((StringRepresentable) e) + .getSerializedName() + .toUpperCase(Locale.ROOT))) + .toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + return new EnumProperty( + state.getName(), + new ArrayList<>((List) state + .getPossibleValues() + .stream() + .map(e -> ((StringRepresentable) e).getSerializedName()) + .toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else { + throw new IllegalArgumentException("WorldEdit needs an update to support " + state + .getClass() + .getSimpleName()); + } + } + }); @SuppressWarnings({ "rawtypes" }) @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java index 571fc61cc..ded4bcfdd 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java @@ -550,24 +550,42 @@ public final class PaperweightAdapter implements BukkitImplAdapter> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { - @Override - public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else if (state instanceof DirectionProperty) { - return new DirectionalProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).toList()); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - return new EnumProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).toList()); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else { - throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); - } - } - }); + private static final LoadingCache> PROPERTY_CACHE = CacheBuilder + .newBuilder() + .build(new CacheLoader<>() { + @Override + public Property load(net.minecraft.world.level.block.state.properties.Property state) { + if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else if (state instanceof DirectionProperty) { + return new DirectionalProperty( + state.getName(), + new ArrayList<>((List) state + .getPossibleValues() + .stream() + .map(e -> Direction.valueOf(((StringRepresentable) e) + .getSerializedName() + .toUpperCase(Locale.ROOT))) + .toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + return new EnumProperty( + state.getName(), + new ArrayList<>((List) state + .getPossibleValues() + .stream() + .map(e -> ((StringRepresentable) e).getSerializedName()) + .toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else { + throw new IllegalArgumentException("WorldEdit needs an update to support " + state + .getClass() + .getSimpleName()); + } + } + }); @SuppressWarnings({ "rawtypes" }) @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java index 89acd6847..206ade66a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java @@ -557,25 +557,43 @@ public final class PaperweightAdapter implements BukkitImplAdapter> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { - @Override - public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else if (state instanceof DirectionProperty) { - return new DirectionalProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).toList()); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - return new EnumProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).toList()); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else { - throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); - } - } - }); + @SuppressWarnings({"unchecked", "rawtypes"}) + private static final LoadingCache> PROPERTY_CACHE = CacheBuilder + .newBuilder() + .build(new CacheLoader<>() { + @Override + public Property load(net.minecraft.world.level.block.state.properties.Property state) { + if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else if (state instanceof DirectionProperty) { + return new DirectionalProperty( + state.getName(), + new ArrayList<>((List) state + .getPossibleValues() + .stream() + .map(e -> Direction.valueOf(((StringRepresentable) e) + .getSerializedName() + .toUpperCase(Locale.ROOT))) + .toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + return new EnumProperty( + state.getName(), + new ArrayList<>((List) state + .getPossibleValues() + .stream() + .map(e -> ((StringRepresentable) e).getSerializedName()) + .toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else { + throw new IllegalArgumentException("WorldEdit needs an update to support " + state + .getClass() + .getSimpleName()); + } + } + }); @SuppressWarnings({ "rawtypes" }) @Override From 4853a65e7c5159eeade483f8b5403e951e10ce19 Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 28 Jun 2024 21:46:30 +0200 Subject: [PATCH 299/466] feat: implement graceful world bounds check where appropriate (#2804) - closes #2494 --- .../exception/OutsideWorldBoundsException.java | 17 +++++++++++++++++ .../java/com/sk89q/worldedit/WorldEdit.java | 16 ++++++++++++++++ .../worldedit/command/UtilityCommands.java | 14 +++++++++++--- .../exception/WorldEditExceptionConverter.java | 6 ++++++ .../src/main/resources/lang/strings.json | 1 + 5 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/exception/OutsideWorldBoundsException.java diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/exception/OutsideWorldBoundsException.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/exception/OutsideWorldBoundsException.java new file mode 100644 index 000000000..73d871135 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/exception/OutsideWorldBoundsException.java @@ -0,0 +1,17 @@ +package com.fastasyncworldedit.core.exception; + +import com.sk89q.worldedit.WorldEditException; + +public class OutsideWorldBoundsException extends WorldEditException { + + private final int y; + + public OutsideWorldBoundsException(int y) { + this.y = y; + } + + public int y() { + return y; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java index be4c9af8c..402310def 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.exception.BrushRadiusLimitException; +import com.fastasyncworldedit.core.exception.OutsideWorldBoundsException; import com.fastasyncworldedit.core.exception.RadiusLimitException; import com.fastasyncworldedit.core.extension.factory.TransformFactory; import com.fastasyncworldedit.core.extent.ResettableExtent; @@ -46,6 +47,7 @@ import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Locatable; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extension.platform.PlatformManager; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.pattern.Pattern; @@ -523,6 +525,20 @@ public final class WorldEdit { throw new BrushRadiusLimitException(max); } } + + /** + * Check if the given position is contained by the extent's min/max height + * + * @param position Position to check + * @param extent Extent to check in + * @throws OutsideWorldBoundsException If the position is outside the world height limits + * @since TODO + */ + public void checkExtentHeightBounds(BlockVector3 position, Extent extent) { + if (position.y() < extent.getMinY() || position.y() > extent.getMaxY()) { + throw new OutsideWorldBoundsException(position.y()); + } + } //FAWE end /** 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 a289f7cff..c81db21d8 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 @@ -242,6 +242,7 @@ public class UtilityCommands { we.checkMaxRadius(depth, actor); BlockVector3 pos = session.getPlacementPosition(actor); + we.checkExtentHeightBounds(pos, editSession); int affected = editSession.fillDirection(pos, pattern, radius, depth, direction); actor.print(Caption.of("worldedit.fill.created", TextComponent.of(affected))); return affected; @@ -330,6 +331,7 @@ public class UtilityCommands { we.checkMaxRadius(radius, actor); BlockVector3 pos = session.getPlacementPosition(actor); + we.checkExtentHeightBounds(pos, editSession); int affected = editSession.fillXZ(pos, pattern, radius, depth, true); actor.print(Caption.of("worldedit.fillr.created", TextComponent.of(affected))); return affected; @@ -357,7 +359,9 @@ public class UtilityCommands { double radius = radiusExp.evaluate(); radius = Math.max(0, radius); we.checkMaxRadius(radius, actor); - int affected = editSession.drainArea(session.getPlacementPosition(actor), radius, waterlogged, plants); + BlockVector3 pos = session.getPlacementPosition(actor); + we.checkExtentHeightBounds(pos, editSession); + int affected = editSession.drainArea(pos, radius, waterlogged, plants); actor.print(Caption.of("worldedit.drain.drained", TextComponent.of(affected))); return affected; } @@ -376,7 +380,9 @@ public class UtilityCommands { ) throws WorldEditException { radius = Math.max(0, radius); we.checkMaxRadius(radius, actor); - int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.LAVA); + BlockVector3 pos = session.getPlacementPosition(actor); + we.checkExtentHeightBounds(pos, editSession); + int affected = editSession.fixLiquid(pos, radius, BlockTypes.LAVA); actor.print(Caption.of("worldedit.fixlava.fixed", TextComponent.of(affected))); return affected; } @@ -395,7 +401,9 @@ public class UtilityCommands { ) throws WorldEditException { radius = Math.max(0, radius); we.checkMaxRadius(radius, actor); - int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.WATER); + BlockVector3 pos = session.getPlacementPosition(actor); + we.checkExtentHeightBounds(pos, editSession); + int affected = editSession.fixLiquid(pos, radius, BlockTypes.WATER); actor.print(Caption.of("worldedit.fixwater.fixed", TextComponent.of(affected))); return affected; } 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 b07f3f61d..b3b3b5df8 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 @@ -21,6 +21,7 @@ package com.sk89q.worldedit.internal.command.exception; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.exception.BrushRadiusLimitException; +import com.fastasyncworldedit.core.exception.OutsideWorldBoundsException; import com.fastasyncworldedit.core.exception.RadiusLimitException; import com.fastasyncworldedit.core.internal.exception.FaweException; import com.google.common.collect.ImmutableList; @@ -146,6 +147,11 @@ public class WorldEditExceptionConverter extends ExceptionConverterHelper { public void convert(RadiusLimitException e) throws CommandException { throw newCommandException(Caption.of("fawe.error.limit.max-radius", TextComponent.of(e.getMaxRadius())), e); } + + @ExceptionMatch + public void convert(OutsideWorldBoundsException e) throws CommandException { + throw newCommandException(Caption.of("fawe.cancel.reason.world.limit", TextComponent.of(e.y())), e); + } //FAWE end @ExceptionMatch diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index a8dddbdcf..16e10a00d 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -164,6 +164,7 @@ "fawe.cancel.reason.no.region.not.added": "Not added to region", "fawe.cancel.reason.player-only": "This operation requires a player, and cannot be executed from console, or without an actor.", "fawe.cancel.reason.actor-required": "This operation requires an actor.", + "fawe.cancel.reason.world.limit": "This operation cannot be performed at y={0} as it is outside world limits.", "fawe.cancel.worldedit.failed.load.chunk": "Skipped loading chunk: {0};{1}. Try increasing chunk-wait.", "fawe.navigation.no.block": "No block in sight! (or too far)", "fawe.selection.sel.max": "{0} points maximum.", From ff04c93b48c5ab4130b44f47fade13c954bf6668 Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 28 Jun 2024 21:46:51 +0200 Subject: [PATCH 300/466] feat: add option to prevent parsing legacy blocks to the FaweLimit (#2783) - Closes #951 --- .../core/command/tool/scroll/Scroll.java | 1 + .../core/configuration/Settings.java | 5 ++++ .../factory/parser/mask/RichMaskParser.java | 2 +- .../platform/binding/ConsumeBindings.java | 1 + .../core/function/mask/BlockMaskBuilder.java | 26 +++++++++++++++++-- .../core/limit/FaweLimit.java | 6 ++++- .../worldedit/command/GeneralCommands.java | 1 + .../command/argument/FactoryConverter.java | 1 + .../factory/parser/mask/BlocksMaskParser.java | 1 + .../scripting/CraftScriptContext.java | 3 +++ 10 files changed, 43 insertions(+), 4 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/scroll/Scroll.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/scroll/Scroll.java index dd7c23984..8e34d3996 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/scroll/Scroll.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/scroll/Scroll.java @@ -51,6 +51,7 @@ public abstract class Scroll implements ScrollTool { parserContext.setActor(player); parserContext.setWorld(player.getWorld()); parserContext.setSession(session); + parserContext.setTryLegacy(player.getLimit().ALLOW_LEGACY); switch (mode) { case CLIPBOARD: if (arguments.size() != 2) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index 5a10ad344..3b80dcdfa 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -191,6 +191,7 @@ public class Settings extends Config { } } limit.UNIVERSAL_DISALLOWED_BLOCKS &= newLimit.UNIVERSAL_DISALLOWED_BLOCKS; + limit.ALLOW_LEGACY &= newLimit.ALLOW_LEGACY; if (limit.DISALLOWED_BLOCKS == null) { limit.DISALLOWED_BLOCKS = newLimit.DISALLOWED_BLOCKS.isEmpty() ? Collections.emptySet() : new HashSet<>( @@ -439,6 +440,10 @@ public class Settings extends Config { " - If fast-placement is disabled, this may cause edits to be slower." }) public boolean UNIVERSAL_DISALLOWED_BLOCKS = true; + @Comment({ + "If legacy, mumerical, blocks IDs should be able to be used (i.e. 12:2)," + }) + public boolean ALLOW_LEGACY = true; @Comment({ "List of blocks to deny use of. Can be either an entire block type or a block with a specific property value.", "Where block properties are specified, any blockstate with the property will be disallowed (e.g. all directions", diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java index 84437c19a..1b6640ecd 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java @@ -143,7 +143,7 @@ public class RichMaskParser extends FaweParser { int end = command.lastIndexOf(']'); mask = parseFromInput(command.substring(1, end == -1 ? command.length() : end), context); } else { - BlockMaskBuilder builder = new BlockMaskBuilder(); + BlockMaskBuilder builder = new BlockMaskBuilder(context); try { builder.addRegex(full); } catch (InputParseException ignored) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ConsumeBindings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ConsumeBindings.java index c1997bb0d..615f1a586 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ConsumeBindings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ConsumeBindings.java @@ -200,6 +200,7 @@ public class ConsumeBindings extends Bindings { public BaseBlock baseBlock(Actor actor, String argument) { ParserContext parserContext = new ParserContext(); parserContext.setActor(actor); + parserContext.setTryLegacy(actor.getLimit().ALLOW_LEGACY); if (actor instanceof Entity) { Extent extent = ((Entity) actor).getExtent(); if (extent instanceof World) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java index baef7f767..33ea8e3f7 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java @@ -9,6 +9,7 @@ import com.fastasyncworldedit.core.util.MutableCharSequence; import com.fastasyncworldedit.core.util.StringMan; import com.fastasyncworldedit.core.world.block.BlanketBaseBlock; import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.registry.state.AbstractProperty; @@ -53,6 +54,7 @@ public class BlockMaskBuilder { private static final long[] ALL = new long[0]; private final long[][] bitSets; + private final ParserContext context; private boolean[] ordinals; private boolean optimizedStates = true; @@ -60,8 +62,28 @@ public class BlockMaskBuilder { this(new long[BlockTypes.size()][]); } + /** + * Create a new instance with a given {@link ParserContext} to use if parsing regex + * + * @since TODO + */ + public BlockMaskBuilder(ParserContext context) { + this(new long[BlockTypes.size()][], context); + } + protected BlockMaskBuilder(long[][] bitSets) { this.bitSets = bitSets; + this.context = new ParserContext(); + } + + /** + * Create a new instance with a given {@link ParserContext} to use if parsing regex + * + * @since TODO + */ + protected BlockMaskBuilder(long[][] bitSets, ParserContext context) { + this.bitSets = bitSets; + this.context = context; } private boolean handleRegex(BlockType blockType, PropertyKey key, String regex, FuzzyStateAllowingBuilder builder) { @@ -173,7 +195,7 @@ public class BlockMaskBuilder { List blockTypeList; List builders; if (StringMan.isAlphanumericUnd(charSequence)) { - BlockType type = BlockTypes.parse(charSequence.toString()); + BlockType type = BlockTypes.parse(charSequence.toString(), context); blockTypeList = Collections.singletonList(type); builders = Collections.singletonList(new FuzzyStateAllowingBuilder(type)); add(type); @@ -280,7 +302,7 @@ public class BlockMaskBuilder { } } else { if (StringMan.isAlphanumericUnd(input)) { - add(BlockTypes.parse(input)); + add(BlockTypes.parse(input, context)); } else { boolean success = false; for (BlockType myType : BlockTypesCache.values) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java index e30ee4db6..d17787f03 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java @@ -28,6 +28,7 @@ public class FaweLimit { public boolean FAST_PLACEMENT = false; public boolean CONFIRM_LARGE = true; public boolean RESTRICT_HISTORY_TO_REGIONS = true; + public boolean ALLOW_LEGACY = true; public Set STRIP_NBT = null; public boolean UNIVERSAL_DISALLOWED_BLOCKS = true; public Set DISALLOWED_BLOCKS = null; @@ -127,6 +128,7 @@ public class FaweLimit { MAX.RESTRICT_HISTORY_TO_REGIONS = false; MAX.STRIP_NBT = Collections.emptySet(); MAX.UNIVERSAL_DISALLOWED_BLOCKS = false; + MAX.ALLOW_LEGACY = true; MAX.DISALLOWED_BLOCKS = Collections.emptySet(); MAX.REMAP_PROPERTIES = Collections.emptySet(); MAX.MAX_RADIUS = Integer.MAX_VALUE; @@ -259,13 +261,13 @@ public class FaweLimit { && !RESTRICT_HISTORY_TO_REGIONS && (STRIP_NBT == null || STRIP_NBT.isEmpty()) // && !UNIVERSAL_DISALLOWED_BLOCKS --> do not include this, it effectively has no relevance + && ALLOW_LEGACY && (DISALLOWED_BLOCKS == null || DISALLOWED_BLOCKS.isEmpty()) && (REMAP_PROPERTIES == null || REMAP_PROPERTIES.isEmpty()) && MAX_RADIUS == Integer.MAX_VALUE && MAX_SUPER_PICKAXE_SIZE == Integer.MAX_VALUE && MAX_BRUSH_RADIUS == Integer.MAX_VALUE && MAX_BUTCHER_RADIUS == Integer.MAX_VALUE; - } public void set(FaweLimit limit) { @@ -286,6 +288,7 @@ public class FaweLimit { RESTRICT_HISTORY_TO_REGIONS = limit.RESTRICT_HISTORY_TO_REGIONS; STRIP_NBT = limit.STRIP_NBT; UNIVERSAL_DISALLOWED_BLOCKS = limit.UNIVERSAL_DISALLOWED_BLOCKS; + ALLOW_LEGACY = limit.ALLOW_LEGACY; DISALLOWED_BLOCKS = limit.DISALLOWED_BLOCKS; REMAP_PROPERTIES = limit.REMAP_PROPERTIES; MAX_RADIUS = limit.MAX_RADIUS; @@ -313,6 +316,7 @@ public class FaweLimit { limit.RESTRICT_HISTORY_TO_REGIONS = RESTRICT_HISTORY_TO_REGIONS; limit.STRIP_NBT = STRIP_NBT; limit.UNIVERSAL_DISALLOWED_BLOCKS = UNIVERSAL_DISALLOWED_BLOCKS; + limit.ALLOW_LEGACY = ALLOW_LEGACY; limit.DISALLOWED_BLOCKS = DISALLOWED_BLOCKS; limit.REMAP_PROPERTIES = REMAP_PROPERTIES; limit.MAX_RADIUS = MAX_RADIUS; 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 3b271a1ec..865e6f937 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 @@ -510,6 +510,7 @@ public class GeneralCommands { parserContext.setWorld(worldArg); parserContext.setSession(session); parserContext.setExtent(editSession); + parserContext.setTryLegacy(actor.getLimit().ALLOW_LEGACY); Mask mask = worldEdit.getMaskFactory().parseFromInput(arg, parserContext); util = TextureUtil.fromMask(mask); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java index d82d25394..d3189f1f1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java @@ -133,6 +133,7 @@ public class FactoryConverter implements ArgumentConverter { parserContext.setSession(session); parserContext.setRestricted(true); parserContext.setInjected(context); + parserContext.setTryLegacy(actor.getLimit().ALLOW_LEGACY); if (contextTweaker != null) { contextTweaker.accept(parserContext); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java index de6eea718..ac94b12d4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java @@ -49,6 +49,7 @@ public class BlocksMaskParser extends InputParser { ParserContext tempContext = new ParserContext(context); tempContext.setRestricted(false); tempContext.setPreferringWildcard(true); + tempContext.setTryLegacy(context.isTryingLegacy()); try { Set holders = worldEdit.getBlockFactory().parseFromListInput(component, tempContext); if (holders.isEmpty()) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/CraftScriptContext.java b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/CraftScriptContext.java index 8eb6df755..4358a6932 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/CraftScriptContext.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/CraftScriptContext.java @@ -183,6 +183,7 @@ public class CraftScriptContext extends CraftScriptEnvironment { context.setSession(session); context.setRestricted(!allAllowed); context.setPreferringWildcard(false); + context.setTryLegacy(player.getLimit().ALLOW_LEGACY); return controller.getBlockFactory().parseFromListInput(input, context).stream().findFirst().orElse(null); } @@ -212,6 +213,7 @@ public class CraftScriptContext extends CraftScriptEnvironment { context.setActor(player); context.setWorld(player.getWorld()); context.setSession(session); + context.setTryLegacy(player.getLimit().ALLOW_LEGACY); return controller.getPatternFactory().parseFromInput(list, context); } @@ -230,6 +232,7 @@ public class CraftScriptContext extends CraftScriptEnvironment { context.setWorld(player.getWorld()); context.setSession(session); context.setRestricted(!allBlocksAllowed); + context.setTryLegacy(player.getLimit().ALLOW_LEGACY); return controller.getBlockFactory().parseFromListInput(list, context); } From 2ccfd50546dc71c86b7417338a0c135e66bcd34d Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 30 Jun 2024 10:40:13 +0200 Subject: [PATCH 301/466] feat: implement 1.21 (#2808) * feat: implement 1.21 * fix: adjust mojang mapped field name in ChunkMap * Fix property cache --------- Co-authored-by: Pierre Maurice Schwang --- build.gradle.kts | 2 +- buildSrc/src/main/kotlin/CommonJavaConfig.kt | 2 +- gradle/libs.versions.toml | 2 +- settings.gradle.kts | 2 +- .../adapters/adapter-1_21/build.gradle.kts | 17 + .../ext/fawe/v1_21_R1/PaperweightAdapter.java | 1158 +++++++ .../v1_21_R1/PaperweightDataConverters.java | 2795 +++++++++++++++++ .../fawe/v1_21_R1/PaperweightFakePlayer.java | 91 + .../PaperweightWorldNativeAccess.java | 191 ++ .../ext/fawe/v1_21_R1/StaticRefraction.java | 90 + .../v1_21_R1/PaperweightBlockMaterial.java | 176 ++ .../fawe/v1_21_R1/PaperweightFaweAdapter.java | 639 ++++ .../PaperweightFaweWorldNativeAccess.java | 293 ++ .../fawe/v1_21_R1/PaperweightGetBlocks.java | 1186 +++++++ .../v1_21_R1/PaperweightGetBlocks_Copy.java | 260 ++ .../v1_21_R1/PaperweightMapChunkUtil.java | 34 + .../v1_21_R1/PaperweightPlatformAdapter.java | 727 +++++ .../v1_21_R1/PaperweightPostProcessor.java | 175 ++ .../PaperweightStarlightRelighter.java | 79 + .../PaperweightStarlightRelighterFactory.java | 25 + .../nbt/PaperweightLazyCompoundTag.java | 161 + .../fawe/v1_21_R1/regen/PaperweightRegen.java | 623 ++++ worldedit-bukkit/build.gradle.kts | 2 +- 23 files changed, 8725 insertions(+), 5 deletions(-) create mode 100644 worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightDataConverters.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightFakePlayer.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightWorldNativeAccess.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/StaticRefraction.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightBlockMaterial.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweWorldNativeAccess.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks_Copy.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightMapChunkUtil.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPostProcessor.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightStarlightRelighter.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightStarlightRelighterFactory.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/nbt/PaperweightLazyCompoundTag.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/regen/PaperweightRegen.java diff --git a/build.gradle.kts b/build.gradle.kts index 8fdea3200..0f188deeb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -83,7 +83,7 @@ allprojects { } applyCommonConfiguration() -val supportedVersions = listOf("1.19.4", "1.20", "1.20.4", "1.20.5", "1.20.6") +val supportedVersions = listOf("1.19.4", "1.20", "1.20.4", "1.20.5", "1.20.6", "1.21") tasks { supportedVersions.forEach { diff --git a/buildSrc/src/main/kotlin/CommonJavaConfig.kt b/buildSrc/src/main/kotlin/CommonJavaConfig.kt index fec02d1a0..60860f7f7 100644 --- a/buildSrc/src/main/kotlin/CommonJavaConfig.kt +++ b/buildSrc/src/main/kotlin/CommonJavaConfig.kt @@ -61,7 +61,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean "https://jd.advntr.dev/api/latest/", "https://logging.apache.org/log4j/2.x/javadoc/log4j-api/", "https://www.antlr.org/api/Java/", - "https://jd.papermc.io/paper/1.20.6/", + "https://jd.papermc.io/paper/1.21/", "https://intellectualsites.github.io/fastasyncworldedit-javadocs/worldedit-core/" ) docTitle = "${rootProject.name}-${project.description}" + " " + "${rootProject.version}" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4f64aa273..b02ec474b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] # Minecraft expectations -paper = "1.20.6-R0.1-SNAPSHOT" +paper = "1.21-R0.1-SNAPSHOT" fastutil = "8.5.9" guava = "31.1-jre" log4j = "2.19.0" diff --git a/settings.gradle.kts b/settings.gradle.kts index 48318b908..de52de2f9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,7 +2,7 @@ rootProject.name = "FastAsyncWorldEdit" include("worldedit-libs") -listOf("1_19_4", "1_20", "1_20_2", "1_20_4", "1_20_5").forEach { +listOf("1_19_4", "1_20", "1_20_2", "1_20_4", "1_20_5", "1_21").forEach { include("worldedit-bukkit:adapters:adapter-$it") } diff --git a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts new file mode 100644 index 000000000..39ff980f6 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts @@ -0,0 +1,17 @@ +import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension + +plugins { + java +} + +applyPaperweightAdapterConfiguration() + +repositories { + gradlePluginPortal() +} + +dependencies { + // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21-R0.1-SNAPSHOT/ + the().paperDevBundle("1.21-R0.1-20240629.091304-42") + compileOnly(libs.paperlib) +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java new file mode 100644 index 000000000..f66bb1460 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java @@ -0,0 +1,1158 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.google.common.util.concurrent.Futures; +import com.mojang.serialization.Codec; +import com.mojang.serialization.Lifecycle; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extension.platform.Watchdog; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +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.util.SideEffect; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.util.io.file.SafeFiles; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.RegenOptions; +import com.sk89q.worldedit.world.biome.BiomeCategory; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.item.ItemType; +import net.minecraft.Util; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.Registry; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ChunkResult; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.util.RandomSource; +import net.minecraft.util.StringRepresentable; +import net.minecraft.util.thread.BlockableEventLoop; +import net.minecraft.world.Clearable; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelSettings; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.StructureBlockEntity; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.WorldOptions; +import net.minecraft.world.level.storage.LevelStorageSource; +import net.minecraft.world.level.storage.PrimaryLevelData; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.World.Environment; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; +import org.bukkit.generator.ChunkGenerator; +import org.enginehub.linbus.common.LinTagId; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinByteTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinEndTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinLongArrayTag; +import org.enginehub.linbus.tree.LinLongTag; +import org.enginehub.linbus.tree.LinShortTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; +import org.spigotmc.SpigotConfig; +import org.spigotmc.WatchdogThread; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.OptionalInt; +import java.util.OptionalLong; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +public final class PaperweightAdapter implements BukkitImplAdapter { + + private final Logger logger = Logger.getLogger(getClass().getCanonicalName()); + + private final Field serverWorldsField; + private final Method getChunkFutureMethod; + private final Field chunkProviderExecutorField; + private final PaperweightDataConverters dataFixer; + private final Watchdog watchdog; + + private static final RandomSource random = RandomSource.create(); + + // ------------------------------------------------------------------------ + // Code that may break between versions of Minecraft + // ------------------------------------------------------------------------ + + public PaperweightAdapter() throws NoSuchFieldException, NoSuchMethodException { + // A simple test + CraftServer.class.cast(Bukkit.getServer()); + + int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); + if (dataVersion != 3953) { + throw new UnsupportedClassVersionError("Not 1.21!"); + } + + serverWorldsField = CraftServer.class.getDeclaredField("worlds"); + serverWorldsField.setAccessible(true); + + getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod( + StaticRefraction.GET_CHUNK_FUTURE_MAIN_THREAD, + int.class, int.class, ChunkStatus.class, boolean.class + ); + getChunkFutureMethod.setAccessible(true); + + chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField( + StaticRefraction.MAIN_THREAD_PROCESSOR + ); + chunkProviderExecutorField.setAccessible(true); + + this.dataFixer = new PaperweightDataConverters(CraftMagicNumbers.INSTANCE.getDataVersion(), this); + + Watchdog watchdog; + try { + Class.forName("org.spigotmc.WatchdogThread"); + watchdog = new SpigotWatchdog(); + } catch (ClassNotFoundException | NoSuchFieldException e) { + try { + watchdog = new MojangWatchdog(((CraftServer) Bukkit.getServer()).getServer()); + } catch (NoSuchFieldException ex) { + watchdog = null; + } + } + this.watchdog = watchdog; + + try { + Class.forName("org.spigotmc.SpigotConfig"); + SpigotConfig.config.set("world-settings.worldeditregentempworld.verbose", false); + } catch (ClassNotFoundException ignored) { + } + } + + @Override + public DataFixer getDataFixer() { + return this.dataFixer; + } + + /** + * Read the given NBT data into the given tile entity. + * + * @param tileEntity the tile entity + * @param tag the tag + */ + static void readTagIntoTileEntity(net.minecraft.nbt.CompoundTag tag, BlockEntity tileEntity) { + tileEntity.loadWithComponents(tag, MinecraftServer.getServer().registryAccess()); + tileEntity.setChanged(); + } + + /** + * Get the ID string of the given entity. + * + * @param entity the entity + * @return the entity ID + */ + private static String getEntityId(Entity entity) { + return EntityType.getKey(entity.getType()).toString(); + } + + /** + * Create an entity using the given entity ID. + * + * @param id the entity ID + * @param world the world + * @return an entity or null + */ + @Nullable + private static Entity createEntityFromId(String id, net.minecraft.world.level.Level world) { + return EntityType.byString(id).map(t -> t.create(world)).orElse(null); + } + + /** + * Write the given NBT data into the given entity. + * + * @param entity the entity + * @param tag the tag + */ + private static void readTagIntoEntity(net.minecraft.nbt.CompoundTag tag, Entity entity) { + entity.load(tag); + } + + /** + * Write the entity's NBT data to the given tag. + * + * @param entity the entity + * @param tag the tag + */ + private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag tag) { + entity.save(tag); + } + + private static Block getBlockFromType(BlockType blockType) { + return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK).get(ResourceLocation.tryParse(blockType.id())); + } + + private static Item getItemFromType(ItemType itemType) { + return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(itemType.id())); + } + + @Override + public OptionalInt getInternalBlockStateId(BlockData data) { + net.minecraft.world.level.block.state.BlockState state = ((CraftBlockData) data).getState(); + int combinedId = Block.getId(state); + return combinedId == 0 && state.getBlock() != Blocks.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); + } + + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + Block mcBlock = getBlockFromType(state.getBlockType()); + net.minecraft.world.level.block.state.BlockState newState = mcBlock.defaultBlockState(); + Map, Object> states = state.getStates(); + newState = applyProperties(mcBlock.getStateDefinition(), newState, states); + final int combinedId = Block.getId(newState); + return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); + } + + public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) { + int internalId = Block.getId(blockState); + BlockState state = BlockStateIdAccess.getBlockStateById(internalId); + if (state == null) { + state = BukkitAdapter.adapt(CraftBlockData.createData(blockState)); + } + + return state; + } + + public BiomeType adapt(Biome biome) { + var mcBiome = ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getKey(biome); + if (mcBiome == null) { + return null; + } + return BiomeType.REGISTRY.get(mcBiome.toString()); + } + + public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockState) { + int internalId = BlockStateIdAccess.getBlockStateId(blockState); + return Block.stateById(internalId); + } + + @Override + public BlockState getBlock(Location location) { + checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); + return adapt(blockData); + } + + @Override + public BaseBlock getFullBlock(Location location) { + BlockState state = getBlock(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + + // Read the NBT data + BlockEntity te = chunk.getBlockEntity(blockPos); + if (te != null) { + net.minecraft.nbt.CompoundTag tag = te.saveWithId(MinecraftServer.getServer().registryAccess()); + return state.toBaseBlock(LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag))); + } + + return state.toBaseBlock(); + } + + private static final HashMap> biomeTypeToNMSCache = new HashMap<>(); + private static final HashMap, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); + + @Override + public BiomeType getBiome(Location location) { + checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + + return biomeTypeFromNMSCache.computeIfAbsent(chunk.getNoiseBiome(x >> 2, y >> 2, z >> 2), b -> BiomeType.REGISTRY.get(b.unwrapKey().get().location().toString())); + } + + @Override + public void setBiome(Location location, BiomeType biome) { + checkNotNull(location); + checkNotNull(biome); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + chunk.setBiome(x >> 2, y >> 2, z >> 2, biomeTypeToNMSCache.computeIfAbsent(biome, b -> ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(ResourceKey.create(Registries.BIOME, ResourceLocation.parse(b.id()))))); + chunk.setUnsaved(true); + } + + @Override + public WorldNativeAccess createWorldNativeAccess(World world) { + return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle())); + } + + private static net.minecraft.core.Direction adapt(Direction face) { + switch (face) { + case NORTH: + return net.minecraft.core.Direction.NORTH; + case SOUTH: + return net.minecraft.core.Direction.SOUTH; + case WEST: + return net.minecraft.core.Direction.WEST; + case EAST: + return net.minecraft.core.Direction.EAST; + case DOWN: + return net.minecraft.core.Direction.DOWN; + case UP: + default: + return net.minecraft.core.Direction.UP; + } + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private net.minecraft.world.level.block.state.BlockState applyProperties( + StateDefinition stateContainer, + net.minecraft.world.level.block.state.BlockState newState, + Map, Object> states + ) { + for (Map.Entry, Object> state : states.entrySet()) { + net.minecraft.world.level.block.state.properties.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.world.level.block.state.properties.EnumProperty) { + String enumName = (String) value; + value = ((net.minecraft.world.level.block.state.properties.EnumProperty) property) + .getValue(enumName).orElseThrow(() -> + new IllegalStateException( + "Enum property " + property.getName() + " does not contain " + enumName + ) + ); + } + + newState = newState.setValue( + (net.minecraft.world.level.block.state.properties.Property) property, + (Comparable) value + ); + } + return newState; + } + + @Override + public BaseEntity getEntity(org.bukkit.entity.Entity entity) { + checkNotNull(entity); + + CraftEntity craftEntity = ((CraftEntity) entity); + Entity mcEntity = craftEntity.getHandle(); + + // Do not allow creating of passenger entity snapshots, passengers are included in the vehicle entity + if (mcEntity.isPassenger()) { + return null; + } + + String id = getEntityId(mcEntity); + + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + readEntityIntoTag(mcEntity, tag); + return new BaseEntity( + EntityTypes.get(id), + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) + ); + } + + @Nullable + @Override + public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state) { + checkNotNull(location); + checkNotNull(state); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + ServerLevel worldServer = craftWorld.getHandle(); + + String entityId = state.getType().id(); + + LinCompoundTag nativeTag = state.getNbt(); + net.minecraft.nbt.CompoundTag tag; + if (nativeTag != null) { + tag = (net.minecraft.nbt.CompoundTag) fromNativeLin(nativeTag); + removeUnwantedEntityTagsRecursively(tag); + } else { + tag = new net.minecraft.nbt.CompoundTag(); + } + + tag.putString("id", entityId); + + Entity createdEntity = EntityType.loadEntityRecursive(tag, craftWorld.getHandle(), (loadedEntity) -> { + loadedEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + return loadedEntity; + }); + + if (createdEntity != null) { + worldServer.addFreshEntityWithPassengers(createdEntity, SpawnReason.CUSTOM); + return createdEntity.getBukkitEntity(); + } else { + return null; + } + } + + // This removes all unwanted tags from the main entity and all its passengers + private void removeUnwantedEntityTagsRecursively(net.minecraft.nbt.CompoundTag tag) { + for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + + // Adapted from net.minecraft.world.entity.EntityType#loadEntityRecursive + if (tag.contains("Passengers", LinTagId.LIST.id())) { + net.minecraft.nbt.ListTag nbttaglist = tag.getList("Passengers", LinTagId.COMPOUND.id()); + + for (int i = 0; i < nbttaglist.size(); ++i) { + removeUnwantedEntityTagsRecursively(nbttaglist.getCompound(i)); + } + } + } + + @Override + public Component getRichBlockName(BlockType blockType) { + return TranslatableComponent.of(getBlockFromType(blockType).getDescriptionId()); + } + + @Override + public Component getRichItemName(ItemType itemType) { + return TranslatableComponent.of(getItemFromType(itemType).getDescriptionId()); + } + + @Override + public Component getRichItemName(BaseItemStack itemStack) { + return TranslatableComponent.of(CraftItemStack.asNMSCopy(BukkitAdapter.adapt(itemStack)).getDescriptionId()); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private static final LoadingCache> PROPERTY_CACHE = CacheBuilder + .newBuilder() + .build(new CacheLoader<>() { + @Override + public Property load(net.minecraft.world.level.block.state.properties.Property state) { + if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else if (state instanceof DirectionProperty) { + return new DirectionalProperty( + state.getName(), + new ArrayList<>((List) state + .getPossibleValues() + .stream() + .map(e -> Direction.valueOf(((StringRepresentable) e) + .getSerializedName() + .toUpperCase(Locale.ROOT))) + .toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + return new EnumProperty( + state.getName(), + new ArrayList<>((List) state + .getPossibleValues() + .stream() + .map(e -> ((StringRepresentable) e).getSerializedName()) + .toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else { + throw new IllegalArgumentException("WorldEdit needs an update to support " + state + .getClass() + .getSimpleName()); + } + } + }); + + @SuppressWarnings({ "rawtypes" }) + @Override + public Map> getProperties(BlockType blockType) { + Map> properties = new TreeMap<>(); + Block block = getBlockFromType(blockType); + StateDefinition blockStateList = + block.getStateDefinition(); + for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { + Property property = PROPERTY_CACHE.getUnchecked(state); + properties.put(property.getName(), property); + } + return properties; + } + + @Override + public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) { + var structureBlock = new StructureBlockEntity( + new BlockPos(pos.x(), pos.y(), pos.z()), + Blocks.STRUCTURE_BLOCK.defaultBlockState() + ); + structureBlock.setLevel(((CraftPlayer) player).getHandle().level()); + ((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create( + structureBlock, + (blockEntity, registryAccess) -> (net.minecraft.nbt.CompoundTag) fromNativeLin(nbtData) + )); + } + + @Override + public void sendFakeOP(Player player) { + ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( + ((CraftPlayer) player).getHandle(), (byte) 28 + )); + } + + /** + * For serializing and deserializing components. + */ + private static final Codec COMPONENTS_CODEC = DataComponentPatch.CODEC.optionalFieldOf( + "components", DataComponentPatch.EMPTY + ).codec(); + + @Override + public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { + var registryAccess = DedicatedServer.getServer().registryAccess(); + ItemStack stack = new ItemStack( + registryAccess.registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(baseItemStack.getType().id())), + baseItemStack.getAmount() + ); + LinCompoundTag nbt = baseItemStack.getNbt(); + if (nbt != null) { + DataComponentPatch componentPatch = COMPONENTS_CODEC.parse( + registryAccess.createSerializationContext(NbtOps.INSTANCE), + fromNativeLin(nbt) + ).getOrThrow(); + stack.applyComponents(componentPatch); + } + return CraftItemStack.asCraftMirror(stack); + } + + @Override + public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { + var registryAccess = DedicatedServer.getServer().registryAccess(); + final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); + CompoundTag tag = (CompoundTag) COMPONENTS_CODEC.encodeStart( + registryAccess.createSerializationContext(NbtOps.INSTANCE), + nmsStack.getComponentsPatch() + ).getOrThrow(); + return new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)), itemStack.getAmount()); + } + + private final LoadingCache fakePlayers + = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); + + @Override + public boolean simulateItemUse(World world, BlockVector3 position, BaseItem item, Direction face) { + CraftWorld craftWorld = (CraftWorld) world; + ServerLevel worldServer = craftWorld.getHandle(); + ItemStack stack = CraftItemStack.asNMSCopy(adapt( + item instanceof BaseItemStack + ? ((BaseItemStack) item) + : new BaseItemStack(item.getType(), item.getNbtReference(), 1) + )); + + PaperweightFakePlayer fakePlayer; + try { + fakePlayer = fakePlayers.get(worldServer); + } catch (ExecutionException ignored) { + return false; + } + fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); + fakePlayer.absMoveTo(position.x(), position.y(), position.z(), + (float) face.toVector().toYaw(), (float) face.toVector().toPitch()); + + final BlockPos blockPos = new BlockPos(position.x(), position.y(), position.z()); + final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos); + final net.minecraft.core.Direction enumFacing = adapt(face); + BlockHitResult rayTrace = new BlockHitResult(blockVec, enumFacing, blockPos, false); + UseOnContext context = new UseOnContext(fakePlayer, InteractionHand.MAIN_HAND, rayTrace); + InteractionResult result = stack.useOn(context); + if (result != InteractionResult.SUCCESS) { + if (worldServer.getBlockState(blockPos).useItemOn(stack, worldServer, fakePlayer, InteractionHand.MAIN_HAND, rayTrace).consumesAction()) { + result = InteractionResult.SUCCESS; + } else { + result = stack.getItem().use(worldServer, fakePlayer, InteractionHand.MAIN_HAND).getResult(); + } + } + + return result == InteractionResult.SUCCESS; + } + + @Override + public boolean canPlaceAt(World world, BlockVector3 position, BlockState blockState) { + int internalId = BlockStateIdAccess.getBlockStateId(blockState); + net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId); + return blockData.canSurvive(((CraftWorld) world).getHandle(), new BlockPos(position.x(), position.y(), position.z())); + } + + @Override + public boolean regenerate(World bukkitWorld, Region region, Extent extent, RegenOptions options) { + try { + doRegen(bukkitWorld, region, extent, options); + } catch (Exception e) { + throw new IllegalStateException("Regen failed.", e); + } + + return true; + } + + private void doRegen(World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { + Environment env = bukkitWorld.getEnvironment(); + ChunkGenerator gen = bukkitWorld.getGenerator(); + + Path tempDir = Files.createTempDirectory("WorldEditWorldGen"); + LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir); + ResourceKey worldDimKey = getWorldDimKey(env); + try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("worldeditregentempworld", worldDimKey)) { + ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); + PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() + .getWorldData().overworldData(); + WorldOptions originalOpts = levelProperties.worldGenOptions(); + + long seed = options.getSeed().orElse(originalWorld.getSeed()); + WorldOptions newOpts = options.getSeed().isPresent() + ? originalOpts.withSeed(OptionalLong.of(seed)) + : originalOpts; + + LevelSettings newWorldSettings = new LevelSettings( + "worldeditregentempworld", + levelProperties.settings.gameType(), + levelProperties.settings.hardcore(), + levelProperties.settings.difficulty(), + levelProperties.settings.allowCommands(), + levelProperties.settings.gameRules(), + levelProperties.settings.getDataConfiguration() + ); + + @SuppressWarnings("deprecation") + PrimaryLevelData.SpecialWorldProperty specialWorldProperty = + levelProperties.isFlatWorld() + ? PrimaryLevelData.SpecialWorldProperty.FLAT + : levelProperties.isDebugWorld() + ? PrimaryLevelData.SpecialWorldProperty.DEBUG + : PrimaryLevelData.SpecialWorldProperty.NONE; + + PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable()); + + ServerLevel freshWorld = new ServerLevel( + originalWorld.getServer(), + originalWorld.getServer().executor, + session, newWorldData, + originalWorld.dimension(), + new LevelStem( + originalWorld.dimensionTypeRegistration(), + originalWorld.getChunkSource().getGenerator() + ), + new NoOpWorldLoadListener(), + originalWorld.isDebug(), + seed, + ImmutableList.of(), + false, + originalWorld.getRandomSequences(), + env, + gen, + bukkitWorld.getBiomeProvider() + ); + try { + regenForWorld(region, extent, freshWorld, options); + } finally { + freshWorld.getChunkSource().close(false); + } + } finally { + try { + @SuppressWarnings("unchecked") + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); + map.remove("worldeditregentempworld"); + } catch (IllegalAccessException ignored) { + } + SafeFiles.tryHardToDeleteDir(tempDir); + } + } + + private BiomeType adapt(ServerLevel serverWorld, Biome origBiome) { + ResourceLocation key = serverWorld.registryAccess().registryOrThrow(Registries.BIOME).getKey(origBiome); + if (key == null) { + return null; + } + return BiomeTypes.get(key.toString()); + } + + @SuppressWarnings("unchecked") + private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld, RegenOptions options) throws WorldEditException { + List> chunkLoadings = submitChunkLoadTasks(region, serverWorld); + BlockableEventLoop executor; + try { + executor = (BlockableEventLoop) chunkProviderExecutorField.get(serverWorld.getChunkSource()); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Couldn't get executor for chunk loading.", e); + } + executor.managedBlock(() -> { + // bail out early if a future fails + if (chunkLoadings.stream().anyMatch(ftr -> + ftr.isDone() && Futures.getUnchecked(ftr) == null + )) { + return false; + } + return chunkLoadings.stream().allMatch(CompletableFuture::isDone); + }); + Map chunks = new HashMap<>(); + for (CompletableFuture future : chunkLoadings) { + @Nullable + ChunkAccess chunk = future.getNow(null); + checkState(chunk != null, "Failed to generate a chunk, regen failed."); + chunks.put(chunk.getPos(), chunk); + } + + for (BlockVector3 vec : region) { + BlockPos pos = new BlockPos(vec.x(), vec.y(), vec.z()); + ChunkAccess chunk = chunks.get(new ChunkPos(pos)); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(pos); + int internalId = Block.getId(blockData); + BlockStateHolder state = BlockStateIdAccess.getBlockStateById(internalId); + Objects.requireNonNull(state); + BlockEntity blockEntity = chunk.getBlockEntity(pos); + if (blockEntity != null) { + net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(serverWorld.registryAccess()); + state = state.toBaseBlock(LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag))); + } + extent.setBlock(vec, state.toBaseBlock()); + if (options.shouldRegenBiomes()) { + Biome origBiome = chunk.getNoiseBiome(vec.x(), vec.y(), vec.z()).value(); + BiomeType adaptedBiome = adapt(serverWorld, origBiome); + if (adaptedBiome != null) { + extent.setBiome(vec, adaptedBiome); + } + } + } + } + + @SuppressWarnings("unchecked") + private List> submitChunkLoadTasks(Region region, ServerLevel serverWorld) { + ServerChunkCache chunkManager = serverWorld.getChunkSource(); + List> chunkLoadings = new ArrayList<>(); + // Pre-gen all the chunks + for (BlockVector2 chunk : region.getChunks()) { + try { + //noinspection unchecked + chunkLoadings.add( + ((CompletableFuture>) + getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) + .thenApply(either -> either.orElse(null)) + ); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException("Couldn't load chunk for regen.", e); + } + } + return chunkLoadings; + } + + private ResourceKey getWorldDimKey(Environment env) { + switch (env) { + case NETHER: + return LevelStem.NETHER; + case THE_END: + return LevelStem.END; + case NORMAL: + default: + return LevelStem.OVERWORLD; + } + } + + private static final Set SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( + SideEffect.NEIGHBORS, + SideEffect.LIGHTING, + SideEffect.VALIDATION, + SideEffect.ENTITY_AI, + SideEffect.EVENTS, + SideEffect.UPDATE + ); + + @Override + public Set getSupportedSideEffects() { + return SUPPORTED_SIDE_EFFECTS; + } + + @Override + public boolean clearContainerBlockContents(World world, BlockVector3 pt) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + + BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z())); + if (entity instanceof Clearable) { + ((Clearable) entity).clearContent(); + return true; + } + return false; + } + + @Override + public void initializeRegistries() { + DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer(); + // Biomes + for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.BIOME).keySet()) { + if (BiomeType.REGISTRY.get(name.toString()) == null) { + BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString())); + } + } + + // BiomeCategories + Registry biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); + biomeRegistry.getTagNames().forEach(tagKey -> { + String key = tagKey.location().toString(); + if (BiomeCategory.REGISTRY.get(key) == null) { + BiomeCategory.REGISTRY.register(key, new BiomeCategory( + key, + () -> biomeRegistry.getTag(tagKey) + .stream() + .flatMap(HolderSet.Named::stream) + .map(Holder::value) + .map(this::adapt) + .collect(Collectors.toSet())) + ); + } + }); + } + + @Override + public void sendBiomeUpdates(World world, Iterable chunks) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + + List nativeChunks = chunks instanceof Collection chunkCollection ? Lists.newArrayListWithCapacity(chunkCollection.size()) : Lists.newArrayList(); + for (BlockVector2 chunk : chunks) { + nativeChunks.add(originalWorld.getChunk(chunk.x(), chunk.z(), ChunkStatus.BIOMES, false)); + } + originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks); + } + + // ------------------------------------------------------------------------ + // Code that is less likely to break + // ------------------------------------------------------------------------ + + /** + * Converts from a non-native NMS NBT structure to a native WorldEdit NBT + * structure. + * + * @param foreign non-native NMS NBT structure + * @return native WorldEdit NBT structure + */ + @Override + public LinTag toNativeLin(net.minecraft.nbt.Tag foreign) { + if (foreign == null) { + return null; + } + if (foreign instanceof net.minecraft.nbt.CompoundTag) { + Map> values = new HashMap<>(); + Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); + + for (String str : foreignKeys) { + net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); + values.put(str, toNativeLin(base)); + } + return LinCompoundTag.of(values); + } else if (foreign instanceof net.minecraft.nbt.ByteTag) { + return LinByteTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); + } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { + return LinByteArrayTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); + } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { + return LinDoubleTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); + } else if (foreign instanceof net.minecraft.nbt.FloatTag) { + return LinFloatTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); + } else if (foreign instanceof net.minecraft.nbt.IntTag) { + return LinIntTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); + } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { + return LinIntArrayTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); + } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { + return LinLongArrayTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); + } else if (foreign instanceof net.minecraft.nbt.ListTag) { + try { + return toNativeLinList((net.minecraft.nbt.ListTag) foreign); + } catch (Throwable e) { + logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); + } + } else if (foreign instanceof net.minecraft.nbt.LongTag) { + return LinLongTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); + } else if (foreign instanceof net.minecraft.nbt.ShortTag) { + return LinShortTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); + } else if (foreign instanceof net.minecraft.nbt.StringTag) { + return LinStringTag.of(foreign.getAsString()); + } else if (foreign instanceof net.minecraft.nbt.EndTag) { + return LinEndTag.instance(); + } + throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); + } + + /** + * Convert a foreign NBT list tag into a native WorldEdit one. + * + * @param foreign the foreign tag + * @return the converted tag + * @throws SecurityException on error + * @throws IllegalArgumentException on error + */ + private LinListTag toNativeLinList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { + LinListTag.Builder> builder = LinListTag.builder( + LinTagType.fromId(LinTagId.fromId(foreign.getElementType())) + ); + + for (net.minecraft.nbt.Tag tag : foreign) { + builder.add(toNativeLin(tag)); + } + + return builder.build(); + } + + /** + * Converts a WorldEdit-native NBT structure to a NMS structure. + * + * @param foreign structure to convert + * @return non-native structure + */ + @Override + public net.minecraft.nbt.Tag fromNativeLin(LinTag foreign) { + if (foreign == null) { + return null; + } + if (foreign instanceof LinCompoundTag compoundTag) { + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + for (var entry : compoundTag.value().entrySet()) { + tag.put(entry.getKey(), fromNativeLin(entry.getValue())); + } + return tag; + } else if (foreign instanceof LinByteTag byteTag) { + return net.minecraft.nbt.ByteTag.valueOf(byteTag.valueAsByte()); + } else if (foreign instanceof LinByteArrayTag byteArrayTag) { + return new net.minecraft.nbt.ByteArrayTag(byteArrayTag.value()); + } else if (foreign instanceof LinDoubleTag doubleTag) { + return net.minecraft.nbt.DoubleTag.valueOf(doubleTag.valueAsDouble()); + } else if (foreign instanceof LinFloatTag floatTag) { + return net.minecraft.nbt.FloatTag.valueOf(floatTag.valueAsFloat()); + } else if (foreign instanceof LinIntTag intTag) { + return net.minecraft.nbt.IntTag.valueOf(intTag.valueAsInt()); + } else if (foreign instanceof LinIntArrayTag intArrayTag) { + return new net.minecraft.nbt.IntArrayTag(intArrayTag.value()); + } else if (foreign instanceof LinLongArrayTag longArrayTag) { + return new net.minecraft.nbt.LongArrayTag(longArrayTag.value()); + } else if (foreign instanceof LinListTag listTag) { + net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); + for (var t : listTag.value()) { + tag.add(fromNativeLin(t)); + } + return tag; + } else if (foreign instanceof LinLongTag longTag) { + return net.minecraft.nbt.LongTag.valueOf(longTag.valueAsLong()); + } else if (foreign instanceof LinShortTag shortTag) { + return net.minecraft.nbt.ShortTag.valueOf(shortTag.valueAsShort()); + } else if (foreign instanceof LinStringTag stringTag) { + return net.minecraft.nbt.StringTag.valueOf(stringTag.value()); + } else if (foreign instanceof LinEndTag) { + return net.minecraft.nbt.EndTag.INSTANCE; + } else { + throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); + } + } + + @Override + public boolean supportsWatchdog() { + return watchdog != null; + } + + @Override + public void tickWatchdog() { + watchdog.tick(); + } + + private class SpigotWatchdog implements Watchdog { + private final Field instanceField; + private final Field lastTickField; + + SpigotWatchdog() throws NoSuchFieldException { + Field instanceField = WatchdogThread.class.getDeclaredField("instance"); + instanceField.setAccessible(true); + this.instanceField = instanceField; + + Field lastTickField = WatchdogThread.class.getDeclaredField("lastTick"); + lastTickField.setAccessible(true); + this.lastTickField = lastTickField; + } + + @Override + public void tick() { + try { + WatchdogThread instance = (WatchdogThread) this.instanceField.get(null); + if ((long) lastTickField.get(instance) != 0) { + WatchdogThread.tick(); + } + } catch (IllegalAccessException e) { + logger.log(Level.WARNING, "Failed to tick watchdog", e); + } + } + } + + private static class MojangWatchdog implements Watchdog { + private final DedicatedServer server; + private final Field tickField; + + MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { + this.server = server; + Field tickField = MinecraftServer.class.getDeclaredField(StaticRefraction.NEXT_TICK_TIME); + if (tickField.getType() != long.class) { + throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); + } + tickField.setAccessible(true); + this.tickField = tickField; + } + + @Override + public void tick() { + try { + tickField.set(server, Util.getMillis()); + } catch (IllegalAccessException ignored) { + } + } + } + + private static class NoOpWorldLoadListener implements ChunkProgressListener { + @Override + public void updateSpawnPos(ChunkPos spawnPos) { + } + + @Override + public void onStatusChange(ChunkPos pos, @org.jetbrains.annotations.Nullable ChunkStatus status) { + } + + @Override + public void start() { + } + + @Override + public void stop() { + } + + } +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightDataConverters.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightDataConverters.java new file mode 100644 index 000000000..e84ba0d4e --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightDataConverters.java @@ -0,0 +1,2795 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1; + +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.schemas.Schema; +import com.mojang.serialization.Dynamic; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.FloatTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.GsonHelper; +import net.minecraft.util.StringUtil; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.world.item.DyeColor; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinCompoundTag; + +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.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({ "rawtypes", "unchecked" }) +class PaperweightDataConverters 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((LinCompoundTag) original, srcVer); + } else if (type == FixTypes.BLOCK_ENTITY) { + return (T) fixBlockEntity((LinCompoundTag) original, srcVer); + } else if (type == FixTypes.ENTITY) { + return (T) fixEntity((LinCompoundTag) 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 LinCompoundTag fixChunk(LinCompoundTag originalChunk, int srcVer) { + CompoundTag tag = (CompoundTag) adapter.fromNativeLin(originalChunk); + CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); + return (LinCompoundTag) adapter.toNativeLin(fixed); + } + + private LinCompoundTag fixBlockEntity(LinCompoundTag origTileEnt, int srcVer) { + CompoundTag tag = (CompoundTag) adapter.fromNativeLin(origTileEnt); + CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); + return (LinCompoundTag) adapter.toNativeLin(fixed); + } + + private LinCompoundTag fixEntity(LinCompoundTag origEnt, int srcVer) { + CompoundTag tag = (CompoundTag) adapter.fromNativeLin(origEnt); + CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); + return (LinCompoundTag) adapter.toNativeLin(fixed); + } + + private String fixBlockState(String blockState, int srcVer) { + CompoundTag stateNBT = stateToNBT(blockState); + Dynamic dynamic = new Dynamic<>(OPS_NBT, stateNBT); + CompoundTag fixed = (CompoundTag) INSTANCE.fixer.update(References.BLOCK_STATE, dynamic, srcVer, DATA_VERSION).getValue(); + return nbtToState(fixed); + } + + private String nbtToState(CompoundTag tagCompound) { + StringBuilder sb = new StringBuilder(); + sb.append(tagCompound.getString("Name")); + if (tagCompound.contains("Properties", 10)) { + sb.append('['); + CompoundTag props = tagCompound.getCompound("Properties"); + sb.append(props.getAllKeys().stream().map(k -> k + "=" + props.getString(k).replace("\"", "")).collect(Collectors.joining(","))); + sb.append(']'); + } + return sb.toString(); + } + + private static CompoundTag stateToNBT(String blockState) { + int propIdx = blockState.indexOf('['); + CompoundTag tag = new CompoundTag(); + if (propIdx < 0) { + tag.putString("Name", blockState); + } else { + tag.putString("Name", blockState.substring(0, propIdx)); + CompoundTag propTag = new 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, References.BIOME); + } + + private String fixItemType(String key, int srcVer) { + return fixName(key, srcVer, References.ITEM_NAME); + } + + private static String fixName(String key, int srcVer, TypeReference type) { + return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, StringTag.valueOf(key)), srcVer, DATA_VERSION) + .getValue().getAsString(); + } + + private final PaperweightAdapter adapter; + + private static final NbtOps OPS_NBT = NbtOps.INSTANCE; + private static final int LEGACY_VERSION = 1343; + private static int DATA_VERSION; + static PaperweightDataConverters 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(References.LEVEL), + PLAYER(References.PLAYER), + CHUNK(References.CHUNK), + BLOCK_ENTITY(References.BLOCK_ENTITY), + ENTITY(References.ENTITY), + ITEM_INSTANCE(References.ITEM_STACK), + OPTIONS(References.OPTIONS), + STRUCTURE(References.STRUCTURE); + + private final TypeReference type; + + LegacyType(TypeReference type) { + this.type = type; + DFU_TO_LEGACY.put(type.typeName(), this); + } + + public TypeReference getDFUType() { + return type; + } + } + + PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { + DATA_VERSION = dataVersion; + INSTANCE = this; + this.adapter = adapter; + registerConverters(); + registerInspectors(); + this.fixer = new WrappedDataFixer(DataFixers.getDataFixer()); + } + + @SuppressWarnings("unchecked") + 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) { + CompoundTag cmp = (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 CompoundTag convert(LegacyType type, CompoundTag cmp, int sourceVer, int desiredVersion) { + List converters = PaperweightDataConverters.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 = PaperweightDataConverters.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 CompoundTag convert(LegacyType type, CompoundTag cmp) { + return convert(type.getDFUType(), cmp); + } + + public static CompoundTag convert(LegacyType type, CompoundTag cmp, int sourceVer) { + return convert(type.getDFUType(), cmp, sourceVer); + } + + public static CompoundTag convert(LegacyType type, CompoundTag cmp, int sourceVer, int targetVer) { + return convert(type.getDFUType(), cmp, sourceVer, targetVer); + } + + public static CompoundTag convert(TypeReference type, CompoundTag cmp) { + int i = cmp.contains("DataVersion", 99) ? cmp.getInt("DataVersion") : -1; + return convert(type, cmp, i); + } + + public static CompoundTag convert(TypeReference type, CompoundTag cmp, int sourceVer) { + return convert(type, cmp, sourceVer, DATA_VERSION); + } + + public static CompoundTag convert(TypeReference type, CompoundTag cmp, int sourceVer, int targetVer) { + if (sourceVer >= targetVer) { + return cmp; + } + return (CompoundTag) INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, cmp), sourceVer, targetVer).getValue(); + } + + + public interface DataInspector { + CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer); + } + + public interface DataConverter { + + int getDataVersion(); + + CompoundTag convert(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", ResourceLocation.parse("item")); + map.put("EntityExperienceOrb", ResourceLocation.parse("xp_orb")); + map.put("EntityAreaEffectCloud", ResourceLocation.parse("area_effect_cloud")); + map.put("EntityGuardianElder", ResourceLocation.parse("elder_guardian")); + map.put("EntitySkeletonWither", ResourceLocation.parse("wither_skeleton")); + map.put("EntitySkeletonStray", ResourceLocation.parse("stray")); + map.put("EntityEgg", ResourceLocation.parse("egg")); + map.put("EntityLeash", ResourceLocation.parse("leash_knot")); + map.put("EntityPainting", ResourceLocation.parse("painting")); + map.put("EntityTippedArrow", ResourceLocation.parse("arrow")); + map.put("EntitySnowball", ResourceLocation.parse("snowball")); + map.put("EntityLargeFireball", ResourceLocation.parse("fireball")); + map.put("EntitySmallFireball", ResourceLocation.parse("small_fireball")); + map.put("EntityEnderPearl", ResourceLocation.parse("ender_pearl")); + map.put("EntityEnderSignal", ResourceLocation.parse("eye_of_ender_signal")); + map.put("EntityPotion", ResourceLocation.parse("potion")); + map.put("EntityThrownExpBottle", ResourceLocation.parse("xp_bottle")); + map.put("EntityItemFrame", ResourceLocation.parse("item_frame")); + map.put("EntityWitherSkull", ResourceLocation.parse("wither_skull")); + map.put("EntityTNTPrimed", ResourceLocation.parse("tnt")); + map.put("EntityFallingBlock", ResourceLocation.parse("falling_block")); + map.put("EntityFireworks", ResourceLocation.parse("fireworks_rocket")); + map.put("EntityZombieHusk", ResourceLocation.parse("husk")); + map.put("EntitySpectralArrow", ResourceLocation.parse("spectral_arrow")); + map.put("EntityShulkerBullet", ResourceLocation.parse("shulker_bullet")); + map.put("EntityDragonFireball", ResourceLocation.parse("dragon_fireball")); + map.put("EntityZombieVillager", ResourceLocation.parse("zombie_villager")); + map.put("EntityHorseSkeleton", ResourceLocation.parse("skeleton_horse")); + map.put("EntityHorseZombie", ResourceLocation.parse("zombie_horse")); + map.put("EntityArmorStand", ResourceLocation.parse("armor_stand")); + map.put("EntityHorseDonkey", ResourceLocation.parse("donkey")); + map.put("EntityHorseMule", ResourceLocation.parse("mule")); + map.put("EntityEvokerFangs", ResourceLocation.parse("evocation_fangs")); + map.put("EntityEvoker", ResourceLocation.parse("evocation_illager")); + map.put("EntityVex", ResourceLocation.parse("vex")); + map.put("EntityVindicator", ResourceLocation.parse("vindication_illager")); + map.put("EntityIllagerIllusioner", ResourceLocation.parse("illusion_illager")); + map.put("EntityMinecartCommandBlock", ResourceLocation.parse("commandblock_minecart")); + map.put("EntityBoat", ResourceLocation.parse("boat")); + map.put("EntityMinecartRideable", ResourceLocation.parse("minecart")); + map.put("EntityMinecartChest", ResourceLocation.parse("chest_minecart")); + map.put("EntityMinecartFurnace", ResourceLocation.parse("furnace_minecart")); + map.put("EntityMinecartTNT", ResourceLocation.parse("tnt_minecart")); + map.put("EntityMinecartHopper", ResourceLocation.parse("hopper_minecart")); + map.put("EntityMinecartMobSpawner", ResourceLocation.parse("spawner_minecart")); + map.put("EntityCreeper", ResourceLocation.parse("creeper")); + map.put("EntitySkeleton", ResourceLocation.parse("skeleton")); + map.put("EntitySpider", ResourceLocation.parse("spider")); + map.put("EntityGiantZombie", ResourceLocation.parse("giant")); + map.put("EntityZombie", ResourceLocation.parse("zombie")); + map.put("EntitySlime", ResourceLocation.parse("slime")); + map.put("EntityGhast", ResourceLocation.parse("ghast")); + map.put("EntityPigZombie", ResourceLocation.parse("zombie_pigman")); + map.put("EntityEnderman", ResourceLocation.parse("enderman")); + map.put("EntityCaveSpider", ResourceLocation.parse("cave_spider")); + map.put("EntitySilverfish", ResourceLocation.parse("silverfish")); + map.put("EntityBlaze", ResourceLocation.parse("blaze")); + map.put("EntityMagmaCube", ResourceLocation.parse("magma_cube")); + map.put("EntityEnderDragon", ResourceLocation.parse("ender_dragon")); + map.put("EntityWither", ResourceLocation.parse("wither")); + map.put("EntityBat", ResourceLocation.parse("bat")); + map.put("EntityWitch", ResourceLocation.parse("witch")); + map.put("EntityEndermite", ResourceLocation.parse("endermite")); + map.put("EntityGuardian", ResourceLocation.parse("guardian")); + map.put("EntityShulker", ResourceLocation.parse("shulker")); + map.put("EntityPig", ResourceLocation.parse("pig")); + map.put("EntitySheep", ResourceLocation.parse("sheep")); + map.put("EntityCow", ResourceLocation.parse("cow")); + map.put("EntityChicken", ResourceLocation.parse("chicken")); + map.put("EntitySquid", ResourceLocation.parse("squid")); + map.put("EntityWolf", ResourceLocation.parse("wolf")); + map.put("EntityMushroomCow", ResourceLocation.parse("mooshroom")); + map.put("EntitySnowman", ResourceLocation.parse("snowman")); + map.put("EntityOcelot", ResourceLocation.parse("ocelot")); + map.put("EntityIronGolem", ResourceLocation.parse("villager_golem")); + map.put("EntityHorse", ResourceLocation.parse("horse")); + map.put("EntityRabbit", ResourceLocation.parse("rabbit")); + map.put("EntityPolarBear", ResourceLocation.parse("polar_bear")); + map.put("EntityLlama", ResourceLocation.parse("llama")); + map.put("EntityLlamaSpit", ResourceLocation.parse("llama_spit")); + map.put("EntityParrot", ResourceLocation.parse("parrot")); + map.put("EntityVillager", ResourceLocation.parse("villager")); + map.put("EntityEnderCrystal", ResourceLocation.parse("ender_crystal")); + map.put("TileEntityFurnace", ResourceLocation.parse("furnace")); + map.put("TileEntityChest", ResourceLocation.parse("chest")); + map.put("TileEntityEnderChest", ResourceLocation.parse("ender_chest")); + map.put("TileEntityRecordPlayer", ResourceLocation.parse("jukebox")); + map.put("TileEntityDispenser", ResourceLocation.parse("dispenser")); + map.put("TileEntityDropper", ResourceLocation.parse("dropper")); + map.put("TileEntitySign", ResourceLocation.parse("sign")); + map.put("TileEntityMobSpawner", ResourceLocation.parse("mob_spawner")); + map.put("TileEntityNote", ResourceLocation.parse("noteblock")); + map.put("TileEntityPiston", ResourceLocation.parse("piston")); + map.put("TileEntityBrewingStand", ResourceLocation.parse("brewing_stand")); + map.put("TileEntityEnchantTable", ResourceLocation.parse("enchanting_table")); + map.put("TileEntityEnderPortal", ResourceLocation.parse("end_portal")); + map.put("TileEntityBeacon", ResourceLocation.parse("beacon")); + map.put("TileEntitySkull", ResourceLocation.parse("skull")); + map.put("TileEntityLightDetector", ResourceLocation.parse("daylight_detector")); + map.put("TileEntityHopper", ResourceLocation.parse("hopper")); + map.put("TileEntityComparator", ResourceLocation.parse("comparator")); + map.put("TileEntityFlowerPot", ResourceLocation.parse("flower_pot")); + map.put("TileEntityBanner", ResourceLocation.parse("banner")); + map.put("TileEntityStructure", ResourceLocation.parse("structure_block")); + map.put("TileEntityEndGateway", ResourceLocation.parse("end_gateway")); + map.put("TileEntityCommand", ResourceLocation.parse("command_block")); + map.put("TileEntityShulkerBox", ResourceLocation.parse("shulker_box")); + map.put("TileEntityBed", ResourceLocation.parse("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, CompoundTag cmp, String key, int sourceVer, int targetVer) { + cmp.put(key, convert(type, cmp.getCompound(key), sourceVer, targetVer)); + } + + private static void convertItem(CompoundTag nbttagcompound, String key, int sourceVer, int targetVer) { + if (nbttagcompound.contains(key, 10)) { + convertCompound(LegacyType.ITEM_INSTANCE, nbttagcompound, key, sourceVer, targetVer); + } + } + + private static void convertItems(CompoundTag nbttagcompound, String key, int sourceVer, int targetVer) { + if (nbttagcompound.contains(key, 9)) { + ListTag nbttaglist = nbttagcompound.getList(key, 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set(j, convert(LegacyType.ITEM_INSTANCE, nbttaglist.getCompound(j), sourceVer, targetVer)); + } + } + + } + + private static class DataConverterEquipment implements DataConverter { + + DataConverterEquipment() { + } + + public int getDataVersion() { + return 100; + } + + public CompoundTag convert(CompoundTag cmp) { + ListTag nbttaglist = cmp.getList("Equipment", 10); + ListTag nbttaglist1; + + if (!nbttaglist.isEmpty() && !cmp.contains("HandItems", 10)) { + nbttaglist1 = new ListTag(); + nbttaglist1.add(nbttaglist.get(0)); + nbttaglist1.add(new CompoundTag()); + cmp.put("HandItems", nbttaglist1); + } + + if (nbttaglist.size() > 1 && !cmp.contains("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.contains("DropChances", 9)) { + nbttaglist1 = cmp.getList("DropChances", 5); + ListTag nbttaglist2; + + if (!cmp.contains("HandDropChances", 10)) { + nbttaglist2 = new ListTag(); + nbttaglist2.add(FloatTag.valueOf(nbttaglist1.getFloat(0))); + nbttaglist2.add(FloatTag.valueOf(0.0F)); + cmp.put("HandDropChances", nbttaglist2); + } + + if (!cmp.contains("ArmorDropChances", 10)) { + nbttaglist2 = new ListTag(); + nbttaglist2.add(FloatTag.valueOf(nbttaglist1.getFloat(1))); + nbttaglist2.add(FloatTag.valueOf(nbttaglist1.getFloat(2))); + nbttaglist2.add(FloatTag.valueOf(nbttaglist1.getFloat(3))); + nbttaglist2.add(FloatTag.valueOf(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 = ResourceLocation.parse(s).toString(); + if (i < 515 && DataInspectorBlockEntity.b.containsKey(key)) { + return DataInspectorBlockEntity.b.get(key); + } else { + return DataInspectorBlockEntity.c.get(key); + } + } + + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + if (!cmp.contains("tag", 10)) { + return cmp; + } else { + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + 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.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 { + + DataInspectorEntity() { + } + + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("EntityTag", 10)) { + 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; + + 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 CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + if (this.key.equals(ResourceLocation.parse(cmp.getString("id")))) { + cmp = this.inspectChecked(cmp, sourceVer, targetVer); + } + + return cmp; + } + + abstract CompoundTag inspectChecked(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; + } + + CompoundTag inspectChecked(CompoundTag nbttagcompound, int sourceVer, int targetVer) { + for (String s : this.keys) { + PaperweightDataConverters.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; + } + + CompoundTag inspectChecked(CompoundTag nbttagcompound, int sourceVer, int targetVer) { + for (String key : this.keys) { + PaperweightDataConverters.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 CompoundTag convert(CompoundTag 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"; + // Paper start + materials[409] = "minecraft:prismarine_shard"; + materials[410] = "minecraft:prismarine_crystals"; + materials[411] = "minecraft:rabbit"; + materials[412] = "minecraft:cooked_rabbit"; + materials[413] = "minecraft:rabbit_stew"; + materials[414] = "minecraft:rabbit_foot"; + materials[415] = "minecraft:rabbit_hide"; + materials[416] = "minecraft:armor_stand"; + materials[423] = "minecraft:mutton"; + materials[424] = "minecraft:cooked_mutton"; + materials[425] = "minecraft:banner"; + materials[426] = "minecraft:end_crystal"; + materials[427] = "minecraft:spruce_door"; + materials[428] = "minecraft:birch_door"; + materials[429] = "minecraft:jungle_door"; + materials[430] = "minecraft:acacia_door"; + materials[431] = "minecraft:dark_oak_door"; + materials[432] = "minecraft:chorus_fruit"; + materials[433] = "minecraft:chorus_fruit_popped"; + materials[434] = "minecraft:beetroot"; + materials[435] = "minecraft:beetroot_seeds"; + materials[436] = "minecraft:beetroot_soup"; + materials[437] = "minecraft:dragon_breath"; + materials[438] = "minecraft:splash_potion"; + materials[439] = "minecraft:spectral_arrow"; + materials[440] = "minecraft:tipped_arrow"; + materials[441] = "minecraft:lingering_potion"; + materials[442] = "minecraft:shield"; + materials[443] = "minecraft:elytra"; + materials[444] = "minecraft:spruce_boat"; + materials[445] = "minecraft:birch_boat"; + materials[446] = "minecraft:jungle_boat"; + materials[447] = "minecraft:acacia_boat"; + materials[448] = "minecraft:dark_oak_boat"; + materials[449] = "minecraft:totem_of_undying"; + materials[450] = "minecraft:shulker_shell"; + materials[452] = "minecraft:iron_nugget"; + materials[453] = "minecraft:knowledge_book"; + // Paper end + } + } + + private static class DataConverterArmorStand implements DataConverter { + + DataConverterArmorStand() { + } + + public int getDataVersion() { + return 147; + } + + public CompoundTag convert(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 CompoundTag convert(CompoundTag cmp) { + if ("minecraft:banner".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + + if (nbttagcompound2.contains("Base", 99)) { + cmp.putShort("Damage", (short) (nbttagcompound2.getShort("Base") & 15)); + if (nbttagcompound1.contains("display", 10)) { + CompoundTag nbttagcompound3 = nbttagcompound1.getCompound("display"); + + if (nbttagcompound3.contains("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 CompoundTag convert(CompoundTag cmp) { + if ("minecraft:potion".equals(cmp.getString("id"))) { + CompoundTag 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 CompoundTag convert(CompoundTag cmp) { + if ("minecraft:spawn_egg".equals(cmp.getString("id"))) { + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + CompoundTag 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("MinecartRideable", "MinecartChest", "MinecartFurnace", "MinecartTNT", "MinecartSpawner", "MinecartHopper", "MinecartCommandBlock"); + + DataConverterMinecart() { + } + + public int getDataVersion() { + return 106; + } + + public CompoundTag convert(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 CompoundTag convert(CompoundTag cmp) { + if (!"MobSpawner".equals(cmp.getString("id"))) { + return cmp; + } else { + if (cmp.contains("EntityId", 8)) { + String s = cmp.getString("EntityId"); + CompoundTag nbttagcompound1 = cmp.getCompound("SpawnData"); + + nbttagcompound1.putString("id", s.isEmpty() ? "Pig" : s); + cmp.put("SpawnData", nbttagcompound1); + cmp.remove("EntityId"); + } + + if (cmp.contains("SpawnPotentials", 9)) { + ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int i = 0; i < nbttaglist.size(); ++i) { + CompoundTag nbttagcompound2 = nbttaglist.getCompound(i); + + if (nbttagcompound2.contains("Type", 8)) { + 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 CompoundTag convert(CompoundTag cmp) { + if (cmp.contains("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 CompoundTag convert(CompoundTag 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 CompoundTag convert(CompoundTag cmp) { + if ("EntityHorse".equals(cmp.getString("id")) && !cmp.contains("SaddleItem", 10) && cmp.getBoolean("Saddle")) { + CompoundTag nbttagcompound1 = new 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 CompoundTag convert(CompoundTag 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.from2DDataValue(cmp.getByte("Direction")); + cmp.putInt("TileX", cmp.getInt("TileX") + enumdirection.getStepX()); + cmp.putInt("TileY", cmp.getInt("TileY") + enumdirection.getStepY()); + cmp.putInt("TileZ", cmp.getInt("TileZ") + enumdirection.getStepZ()); + cmp.remove("Direction"); + if (flag1 && cmp.contains("ItemRotation", 99)) { + cmp.putByte("ItemRotation", (byte) (cmp.getByte("ItemRotation") * 2)); + } + } else { + enumdirection = Direction.from2DDataValue(cmp.getByte("Dir")); + cmp.remove("Dir"); + } + + cmp.putByte("Facing", (byte) enumdirection.get2DDataValue()); + } + + return cmp; + } + } + + private static class DataConverterDropChances implements DataConverter { + + DataConverterDropChances() { + } + + public int getDataVersion() { + return 113; + } + + public CompoundTag convert(CompoundTag cmp) { + ListTag 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 CompoundTag convert(CompoundTag cmp) { + while (cmp.contains("Riding", 10)) { + CompoundTag nbttagcompound1 = this.b(cmp); + + this.convert(cmp, nbttagcompound1); + cmp = nbttagcompound1; + } + + return cmp; + } + + protected void convert(CompoundTag nbttagcompound, CompoundTag nbttagcompound1) { + ListTag nbttaglist = new ListTag(); + + nbttaglist.add(nbttagcompound); + nbttagcompound1.put("Passengers", nbttaglist); + } + + protected CompoundTag b(CompoundTag nbttagcompound) { + CompoundTag nbttagcompound1 = nbttagcompound.getCompound("Riding"); + + nbttagcompound.remove("Riding"); + return nbttagcompound1; + } + } + + private static class DataConverterBook implements DataConverter { + + DataConverterBook() { + } + + public int getDataVersion() { + return 165; + } + + public CompoundTag convert(CompoundTag cmp) { + if ("minecraft:written_book".equals(cmp.getString("id"))) { + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("pages", 9)) { + ListTag nbttaglist = nbttagcompound1.getList("pages", 8); + + for (int i = 0; i < nbttaglist.size(); ++i) { + String s = nbttaglist.getString(i); + Component object = null; + + if (!"null".equals(s) && !StringUtil.isNullOrEmpty(s)) { + if ((s.charAt(0) != 34 || s.charAt(s.length() - 1) != 34) && (s.charAt(0) != 123 || s.charAt(s.length() - 1) != 125)) { + object = Component.literal(s); + } else { + try { + object = GsonHelper.fromJson(DataConverterSignText.a, s, Component.class, true); + if (object == null) { + object = Component.literal(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = Component.Serializer.fromJson(s, MinecraftServer.getServer().registryAccess()); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = Component.Serializer.fromJsonLenient(s, MinecraftServer.getServer().registryAccess()); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = Component.literal(s); + } + } + } else { + object = Component.literal(""); + } + + nbttaglist.set(i, StringTag.valueOf(Component.Serializer.toJson(object, MinecraftServer.getServer().registryAccess()))); + } + + nbttagcompound1.put("pages", nbttaglist); + } + } + + return cmp; + } + } + + private static class DataConverterCookedFish implements DataConverter { + + private static final ResourceLocation a = ResourceLocation.parse("cooked_fished"); + + DataConverterCookedFish() { + } + + public int getDataVersion() { + return 502; + } + + public CompoundTag convert(CompoundTag cmp) { + if (cmp.contains("id", 8) && DataConverterCookedFish.a.equals(ResourceLocation.parse(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 CompoundTag convert(CompoundTag 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 CompoundTag convert(CompoundTag cmp) { + cmp.putString("useVbo", "true"); + return cmp; + } + } + + private static class DataConverterGuardian implements DataConverter { + + DataConverterGuardian() { + } + + public int getDataVersion() { + return 700; + } + + public CompoundTag convert(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 CompoundTag convert(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 CompoundTag convert(CompoundTag cmp) { + if ("Zombie".equals(cmp.getString("id"))) { + int i = cmp.getInt("ZombieType"); + + switch (i) { + case 0: + default: + break; + + 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"); + } + + cmp.remove("ZombieType"); + } + + return cmp; + } + } + + private static class DataConverterHorse implements DataConverter { + + DataConverterHorse() { + } + + public int getDataVersion() { + return 703; + } + + public CompoundTag convert(CompoundTag cmp) { + if ("EntityHorse".equals(cmp.getString("id"))) { + int i = cmp.getInt("Type"); + + switch (i) { + case 0: + default: + cmp.putString("id", "Horse"); + break; + + 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"); + } + + 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 CompoundTag convert(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 CompoundTag convert(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 CompoundTag convert(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)) { + CompoundTag 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 CompoundTag convert(CompoundTag 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 CompoundTag convert(CompoundTag cmp) { + if ("minecraft:shulker_box".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + 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 CompoundTag convert(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 CompoundTag convert(CompoundTag 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 CompoundTag convert(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(PaperweightDataConverters.class); + + DataConverterBedBlock() { + } + + public int getDataVersion() { + return 1125; + } + + public CompoundTag convert(CompoundTag cmp) { + try { + 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) { + CompoundTag 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; + CompoundTag nbttagcompound3 = new 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 CompoundTag convert(CompoundTag cmp) { + if ("minecraft:bed".equals(cmp.getString("id")) && cmp.getShort("Damage") == 0) { + cmp.putShort("Damage", (short) DyeColor.RED.getId()); + } + + return cmp; + } + } + + private static class DataConverterSignText implements DataConverter { + + public static final Gson a = new GsonBuilder().registerTypeAdapter(Component.class, new JsonDeserializer() { + MutableComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { + if (jsonelement.isJsonPrimitive()) { + return Component.literal(jsonelement.getAsString()); + } else if (jsonelement.isJsonArray()) { + JsonArray jsonarray = jsonelement.getAsJsonArray(); + MutableComponent ichatbasecomponent = null; + Iterator iterator = jsonarray.iterator(); + + while (iterator.hasNext()) { + JsonElement jsonelement1 = (JsonElement) iterator.next(); + MutableComponent ichatbasecomponent1 = this.a(jsonelement1, jsonelement1.getClass(), jsondeserializationcontext); + + if (ichatbasecomponent == null) { + ichatbasecomponent = ichatbasecomponent1; + } else { + ichatbasecomponent.append(ichatbasecomponent1); + } + } + + return ichatbasecomponent; + } 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 CompoundTag convert(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(CompoundTag nbttagcompound, String s) { + String s1 = nbttagcompound.getString(s); + Component object = null; + + if (!"null".equals(s1) && !StringUtil.isNullOrEmpty(s1)) { + if ((s1.charAt(0) != 34 || s1.charAt(s1.length() - 1) != 34) && (s1.charAt(0) != 123 || s1.charAt(s1.length() - 1) != 125)) { + object = Component.literal(s1); + } else { + try { + object = GsonHelper.fromJson(DataConverterSignText.a, s1, Component.class, true); + if (object == null) { + object = Component.literal(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = Component.Serializer.fromJson(s1, MinecraftServer.getServer().registryAccess()); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = Component.Serializer.fromJsonLenient(s1, MinecraftServer.getServer().registryAccess()); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = Component.literal(s1); + } + } + } else { + object = Component.literal(""); + } + + nbttagcompound.putString(s, Component.Serializer.toJson(object, MinecraftServer.getServer().registryAccess())); + } + } + + private static class DataInspectorPlayerVehicle implements DataInspector { + @Override + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.contains("RootVehicle", 10)) { + CompoundTag 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 CompoundTag inspect(CompoundTag 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 CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + ListTag nbttaglist; + int j; + CompoundTag nbttagcompound1; + + if (cmp.contains("entities", 9)) { + nbttaglist = cmp.getList("entities", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttagcompound1 = (CompoundTag) 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 = (CompoundTag) 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 CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.contains("Level", 10)) { + CompoundTag nbttagcompound1 = cmp.getCompound("Level"); + ListTag 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, (CompoundTag) 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, (CompoundTag) nbttaglist.get(j), sourceVer, targetVer)); + } + } + } + + return cmp; + } + } + + private static class DataInspectorEntityPassengers implements DataInspector { + @Override + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.contains("Passengers", 9)) { + ListTag 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 CompoundTag inspect(CompoundTag 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 CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + if (entityVillager.equals(ResourceLocation.parse(cmp.getString("id"))) && cmp.contains("Offers", 10)) { + CompoundTag nbttagcompound1 = cmp.getCompound("Offers"); + + if (nbttagcompound1.contains("Recipes", 9)) { + ListTag nbttaglist = nbttagcompound1.getList("Recipes", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + CompoundTag 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 CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + String s = cmp.getString("id"); + if (entityMinecartMobSpawner.equals(ResourceLocation.parse(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 CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + if (tileEntityMobSpawner.equals(ResourceLocation.parse(cmp.getString("id")))) { + if (cmp.contains("SpawnPotentials", 9)) { + ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + CompoundTag 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 CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + if (tileEntityCommand.equals(ResourceLocation.parse(cmp.getString("id")))) { + cmp.putString("id", "Control"); + convert(LegacyType.BLOCK_ENTITY, cmp, sourceVer, targetVer); + cmp.putString("id", "MinecartCommandBlock"); + } + + return cmp; + } + } +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightFakePlayer.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightFakePlayer.java new file mode 100644 index 000000000..d9c89b0e3 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightFakePlayer.java @@ -0,0 +1,91 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1; + +import com.mojang.authlib.GameProfile; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.stats.Stat; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.player.ChatVisiblity; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.phys.Vec3; + +import java.util.OptionalInt; +import java.util.UUID; + +class PaperweightFakePlayer extends ServerPlayer { + private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]"); + private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D); + private static final ClientInformation FAKE_CLIENT_INFO = new ClientInformation( + "en_US", 16, ChatVisiblity.FULL, true, 0, HumanoidArm.LEFT, false, false + ); + + PaperweightFakePlayer(ServerLevel world) { + super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE, FAKE_CLIENT_INFO); + } + + @Override + public Vec3 position() { + return ORIGIN; + } + + @Override + public void tick() { + } + + @Override + public void die(DamageSource damagesource) { + } + + @Override + public OptionalInt openMenu(MenuProvider factory) { + return OptionalInt.empty(); + } + + @Override + public void updateOptions(ClientInformation clientOptions) { + } + + @Override + public void displayClientMessage(Component message, boolean actionBar) { + } + + @Override + public void awardStat(Stat stat, int amount) { + } + + @Override + public void awardStat(Stat stat) { + } + + @Override + public boolean isInvulnerableTo(DamageSource damageSource) { + return true; + } + + @Override + public void openTextEdit(SignBlockEntity sign, boolean front) { + } +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightWorldNativeAccess.java new file mode 100644 index 000000000..d51295053 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightWorldNativeAccess.java @@ -0,0 +1,191 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1; + +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.world.block.BlockState; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.Tag; +import net.minecraft.server.level.FullChunkStatus; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.event.block.BlockPhysicsEvent; +import org.enginehub.linbus.tree.LinCompoundTag; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.util.Objects; + +public class PaperweightWorldNativeAccess implements WorldNativeAccess { + private static final int UPDATE = 1; + private static final int NOTIFY = 2; + + private final PaperweightAdapter adapter; + private final WeakReference world; + private SideEffectSet sideEffectSet; + + public PaperweightWorldNativeAccess(PaperweightAdapter adapter, WeakReference world) { + this.adapter = adapter; + this.world = world; + } + + private ServerLevel getWorld() { + return Objects.requireNonNull(world.get(), "The reference to the world was lost"); + } + + @Override + public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + @Override + public LevelChunk getChunk(int x, int z) { + return getWorld().getChunk(x, z); + } + + @Override + public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) { + int stateId = BlockStateIdAccess.getBlockStateId(state); + return BlockStateIdAccess.isValidInternalId(stateId) + ? Block.stateById(stateId) + : ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); + } + + @Override + public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk chunk, BlockPos position) { + return chunk.getBlockState(position); + } + + @Nullable + @Override + public net.minecraft.world.level.block.state.BlockState setBlockState(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState state) { + return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE)); + } + + @Override + public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(net.minecraft.world.level.block.state.BlockState block, BlockPos position) { + return Block.updateFromNeighbourShapes(block, getWorld(), position); + } + + @Override + public BlockPos getPosition(int x, int y, int z) { + return new BlockPos(x, y, z); + } + + @Override + public void updateLightingForBlock(BlockPos position) { + getWorld().getChunkSource().getLightEngine().checkBlock(position); + } + + @Override + public boolean updateTileEntity(BlockPos position, LinCompoundTag tag) { + // We will assume that the tile entity was created for us + BlockEntity tileEntity = getWorld().getBlockEntity(position); + if (tileEntity == null) { + return false; + } + Tag nativeTag = adapter.fromNativeLin(tag); + PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity); + return true; + } + + @Override + public void notifyBlockUpdate(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { + if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { + getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY); + } + } + + @Override + public boolean isChunkTicking(LevelChunk chunk) { + return chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING); + } + + @Override + public void markBlockChanged(LevelChunk chunk, BlockPos position) { + if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { + getWorld().getChunkSource().blockChanged(position); + } + } + + @Override + public void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { + ServerLevel world = getWorld(); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + world.updateNeighborsAt(pos, oldState.getBlock()); + } else { + // When we don't want events, manually run the physics without them. + Block block = oldState.getBlock(); + fireNeighborChanged(pos, world, block, pos.west()); + fireNeighborChanged(pos, world, block, pos.east()); + fireNeighborChanged(pos, world, block, pos.below()); + fireNeighborChanged(pos, world, block, pos.above()); + fireNeighborChanged(pos, world, block, pos.north()); + fireNeighborChanged(pos, world, block, pos.south()); + } + if (newState.hasAnalogOutputSignal()) { + world.updateNeighbourForOutputSignal(pos, newState.getBlock()); + } + } + + @Override + public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { + ServerLevel world = getWorld(); + newState.onPlace(world, pos, oldState, false); + } + + private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { + world.getBlockState(neighborPos).handleNeighborChanged(world, neighborPos, block, pos, false); + } + + @Override + public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) { + ServerLevel world = getWorld(); + oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + CraftWorld craftWorld = world.getWorld(); + BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState)); + world.getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + } + newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit); + newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); + } + + @Override + public void onBlockStateChange(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { + getWorld().onBlockStateChange(pos, oldState, newState); + } + + @Override + public void flush() { + + } +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/StaticRefraction.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/StaticRefraction.java new file mode 100644 index 000000000..5056a7981 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/StaticRefraction.java @@ -0,0 +1,90 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1; + +import com.sk89q.worldedit.bukkit.adapter.Refraction; + +/** + * Dedicated class to map all names that we use. + * + *

    + * Overloads are split into multiple fields, as they CAN have different obfuscated names. + *

    + */ +public final class StaticRefraction { + public static final String GET_CHUNK_FUTURE_MAIN_THREAD = Refraction.pickName( + "getChunkFutureMainThread", "c" + ); + public static final String MAIN_THREAD_PROCESSOR = Refraction.pickName( + "mainThreadProcessor", "g" + ); + public static final String NEXT_TICK_TIME = Refraction.pickName("nextTickTime", "e"); + public static final String GET_BLOCK_STATE = Refraction.pickName("getBlockState", "a_"); + /** + * {@code addFreshEntityWithPassengers(Entity entity)}. + */ + public static final String ADD_FRESH_ENTITY_WITH_PASSENGERS_ENTITY = Refraction.pickName( + "addFreshEntityWithPassengers", "a_" + ); + /** + * {@code addFreshEntityWithPassengers(Entity entity, CreatureSpawnEvent.SpawnReason reason)}. + */ + public static final String ADD_FRESH_ENTITY_WITH_PASSENGERS_ENTITY_SPAWN_REASON = + Refraction.pickName("addFreshEntityWithPassengers", "a_"); + /** + * {@code addFreshEntity(Entity entity)}. + */ + public static final String ADD_FRESH_ENTITY = Refraction.pickName("addFreshEntity", "b"); + /** + * {@code addFreshEntity(Entity entity, CreatureSpawnEvent.SpawnReason reason)}. + */ + public static final String ADD_FRESH_ENTITY_SPAWN_REASON = Refraction.pickName( + "addFreshEntity", "b" + ); + /** + * {@code getBlockEntity(BlockPos blockPos)}. + */ + public static final String GET_BLOCK_ENTITY = Refraction.pickName("getBlockEntity", "c_"); + /** + * {@code setBlock(BlockPos blockPos, BlockState blockState, int flags)}. + */ + public static final String SET_BLOCK = Refraction.pickName("setBlock", "a"); + /** + * {@code setBlock(BlockPos blockPos, BlockState blockState, int flags, int maxUpdateDepth)}. + */ + public static final String SET_BLOCK_MAX_UPDATE = Refraction.pickName("setBlock", "a"); + public static final String REMOVE_BLOCK = Refraction.pickName("removeBlock", "a"); + /** + * {@code destroyBlock(BlockPos blockPos, boolean drop)}. + */ + public static final String DESTROY_BLOCK = Refraction.pickName("destroyBlock", "b"); + /** + * {@code destroyBlock(BlockPos blockPos, boolean drop, Entity breakingEntity)}. + */ + public static final String DESTROY_BLOCK_BREAKING_ENTITY = Refraction.pickName( + "destroyBlock", "a" + ); + /** + * {@code destroyBlock(BlockPos blockPos, boolean drop, Entity breakingEntity, int maxUpdateDepth)}. + */ + public static final String DESTROY_BLOCK_BREAKING_ENTITY_MAX_UPDATE = Refraction.pickName( + "destroyBlock", "a" + ); +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightBlockMaterial.java new file mode 100644 index 000000000..359527396 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightBlockMaterial.java @@ -0,0 +1,176 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; + +import com.google.common.base.Suppliers; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import net.minecraft.core.BlockPos; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.world.level.EmptyBlockGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.level.material.PushReaction; +import org.bukkit.craftbukkit.block.data.CraftBlockData; + +public class PaperweightBlockMaterial implements BlockMaterial { + + private final Block block; + private final BlockState blockState; + private final CraftBlockData craftBlockData; + private final org.bukkit.Material craftMaterial; + private final int opacity; + private final CompoundTag tile; + + public PaperweightBlockMaterial(Block block) { + this(block, block.defaultBlockState()); + } + + public PaperweightBlockMaterial(Block block, BlockState blockState) { + this.block = block; + this.blockState = blockState; + this.craftBlockData = CraftBlockData.fromData(blockState); + this.craftMaterial = craftBlockData.getMaterial(); + opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); + BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity( + BlockPos.ZERO, + blockState + ); + tile = tileEntity == null ? null : new PaperweightLazyCompoundTag( + Suppliers.memoize(() -> tileEntity.saveWithId(DedicatedServer.getServer().registryAccess())) + ); + } + + public Block getBlock() { + return block; + } + + public BlockState getState() { + return blockState; + } + + public CraftBlockData getCraftBlockData() { + return craftBlockData; + } + + @Override + public boolean isAir() { + return blockState.isAir(); + } + + @Override + public boolean isFullCube() { + return craftMaterial.isOccluding(); + } + + @Override + public boolean isOpaque() { + return blockState.canOcclude(); + } + + @Override + public boolean isPowerSource() { + return blockState.isSignalSource(); + } + + @Override + public boolean isLiquid() { + return !blockState.getFluidState().is(Fluids.EMPTY); + } + + @Override + public boolean isSolid() { + // No access to world -> EmptyBlockGetter + return blockState.isSolidRender(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); + } + + @Override + public float getHardness() { + return craftBlockData.getState().destroySpeed; + } + + @Override + public float getResistance() { + return block.getExplosionResistance(); + } + + @Override + public float getSlipperiness() { + return block.getFriction(); + } + + @Override + public int getLightValue() { + return blockState.getLightEmission(); + } + + @Override + public int getLightOpacity() { + return opacity; + } + + @Override + public boolean isFragileWhenPushed() { + return blockState.getPistonPushReaction() == PushReaction.DESTROY; + } + + @Override + public boolean isUnpushable() { + return blockState.getPistonPushReaction() == PushReaction.BLOCK; + } + + @Override + public boolean isTicksRandomly() { + return blockState.isRandomlyTicking(); + } + + @Override + public boolean isMovementBlocker() { + return craftMaterial.isSolid(); + } + + @Override + public boolean isBurnable() { + return craftMaterial.isBurnable(); + } + + @Override + public boolean isToolRequired() { + // Removed in 1.16.1, this is not present in higher versions + return false; + } + + @Override + public boolean isReplacedDuringPlacement() { + return blockState.canBeReplaced(); + } + + @Override + public boolean isTranslucent() { + return !blockState.canOcclude(); + } + + @Override + public boolean hasContainer() { + return block instanceof EntityBlock; + } + + @Override + public boolean isTile() { + return block instanceof EntityBlock; + } + + @Override + public CompoundTag getDefaultTile() { + return tile; + } + + @Override + public int getMapColor() { + // rgb field + return block.defaultMapColor().col; + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java new file mode 100644 index 000000000..e0dae1b2f --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java @@ -0,0 +1,639 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; + +import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; +import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; +import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.entity.LazyBaseEntity; +import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; +import com.fastasyncworldedit.core.queue.IBatchProcessor; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; +import com.fastasyncworldedit.core.util.NbtUtils; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.mojang.serialization.Codec; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.regen.PaperweightRegen; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +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.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.world.RegenOptions; +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.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import io.papermc.lib.PaperLib; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.WritableRegistry; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.StringRepresentable; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.chunk.LevelChunk; +import org.apache.logging.log4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.World; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.bukkit.entity.Player; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.OptionalInt; +import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static net.minecraft.core.registries.Registries.BIOME; + +public final class PaperweightFaweAdapter extends FaweAdapter { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; + private static final Codec COMPONENTS_CODEC = DataComponentPatch.CODEC.optionalFieldOf( + "components", DataComponentPatch.EMPTY + ).codec(); + + static { + try { + CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE = ChunkHolder.class.getDeclaredMethod("wasAccessibleSinceLastSave"); + } catch (NoSuchMethodException ignored) { // may not be present in newer paper versions + } + } + + private final com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1.PaperweightAdapter parent; + // ------------------------------------------------------------------------ + // Code that may break between versions of Minecraft + // ------------------------------------------------------------------------ + private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil(); + private char[] ibdToStateOrdinal = null; + private int[] ordinalToIbdID = null; + private boolean initialised = false; + private Map>> allBlockProperties = null; + + public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { + this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1.PaperweightAdapter(); + } + + @Nullable + private static String getEntityId(Entity entity) { + ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType()); + return resourceLocation == null ? null : resourceLocation.toString(); + } + + private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { + entity.save(compoundTag); + } + + @Override + public BukkitImplAdapter getParent() { + return parent; + } + + private synchronized boolean init() { + if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) { + return false; + } + ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size + ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size + for (int i = 0; i < ibdToStateOrdinal.length; i++) { + BlockState blockState = BlockTypesCache.states[i]; + PaperweightBlockMaterial material = (PaperweightBlockMaterial) blockState.getMaterial(); + int id = Block.BLOCK_STATE_REGISTRY.getId(material.getState()); + char ordinal = blockState.getOrdinalChar(); + ibdToStateOrdinal[id] = ordinal; + ordinalToIbdID[ordinal] = id; + } + Map>> properties = new HashMap<>(); + try { + for (Field field : BlockStateProperties.class.getDeclaredFields()) { + Object obj = field.get(null); + if (!(obj instanceof net.minecraft.world.level.block.state.properties.Property state)) { + continue; + } + Property property; + if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + property = new BooleanProperty( + state.getName(), + (List) ImmutableList.copyOf(state.getPossibleValues()) + ); + } else if (state instanceof DirectionProperty) { + property = new DirectionalProperty( + state.getName(), + state + .getPossibleValues() + .stream() + .map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase())) + .collect(Collectors.toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + property = new EnumProperty( + state.getName(), + state + .getPossibleValues() + .stream() + .map(e -> ((StringRepresentable) e).getSerializedName()) + .collect(Collectors.toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + property = new IntegerProperty( + state.getName(), + (List) ImmutableList.copyOf(state.getPossibleValues()) + ); + } else { + throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state + .getClass() + .getSimpleName()); + } + properties.compute(property.getName().toLowerCase(Locale.ROOT), (k, v) -> { + if (v == null) { + v = new ArrayList<>(Collections.singletonList(property)); + } else { + v.add(property); + } + return v; + }); + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } finally { + allBlockProperties = ImmutableMap.copyOf(properties); + } + initialised = true; + return true; + } + + @Override + public BlockMaterial getMaterial(BlockType blockType) { + Block block = getBlock(blockType); + return new PaperweightBlockMaterial(block); + } + + @Override + public synchronized BlockMaterial getMaterial(BlockState state) { + net.minecraft.world.level.block.state.BlockState blockState = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState(); + return new PaperweightBlockMaterial(blockState.getBlock(), blockState); + } + + public Block getBlock(BlockType blockType) { + return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK) + .get(ResourceLocation.fromNamespaceAndPath(blockType.getNamespace(), blockType.getResource())); + } + + @Deprecated + @Override + public BlockState getBlock(Location location) { + Preconditions.checkNotNull(location); + + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + final ServerLevel handle = getServerLevel(location.getWorld()); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); + BlockState state = adapt(blockData); + if (state == null) { + org.bukkit.block.Block bukkitBlock = location.getBlock(); + state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } + return state; + } + + @Override + public BaseBlock getFullBlock(final Location location) { + Preconditions.checkNotNull(location); + + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = getServerLevel(location.getWorld()); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); + BlockState state = adapt(blockData); + if (state == null) { + org.bukkit.block.Block bukkitBlock = location.getBlock(); + state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } + if (state.getBlockType().getMaterial().hasContainer()) { + + // Read the NBT data + BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); + if (blockEntity != null) { + net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()); + return state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); + } + } + + return state.toBaseBlock(); + } + + @Override + public Set getSupportedSideEffects() { + return SideEffectSet.defaults().getSideEffectsToApply(); + } + + @Override + public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); + } + + @Override + public BaseEntity getEntity(org.bukkit.entity.Entity entity) { + Preconditions.checkNotNull(entity); + + CraftEntity craftEntity = ((CraftEntity) entity); + Entity mcEntity = craftEntity.getHandle(); + + String id = getEntityId(mcEntity); + + if (id != null) { + EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); + Supplier saveTag = () -> { + final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); + readEntityIntoTag(mcEntity, minecraftTag); + //add Id for AbstractChangeSet to work + final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag); + final Map> tags = NbtUtils.getLinCompoundTagValues(tag); + tags.put("Id", LinStringTag.of(id)); + return LinCompoundTag.of(tags); + }; + return new LazyBaseEntity(type, saveTag); + } else { + return null; + } + } + + @Override + public Component getRichBlockName(BlockType blockType) { + return parent.getRichBlockName(blockType); + } + + @Override + public Component getRichItemName(ItemType itemType) { + return parent.getRichItemName(itemType); + } + + @Override + public Component getRichItemName(BaseItemStack itemStack) { + return parent.getRichItemName(itemStack); + } + + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); + net.minecraft.world.level.block.state.BlockState mcState = material.getCraftBlockData().getState(); + return OptionalInt.of(Block.BLOCK_STATE_REGISTRY.getId(mcState)); + } + + @Override + public BlockState adapt(BlockData blockData) { + CraftBlockData cbd = ((CraftBlockData) blockData); + net.minecraft.world.level.block.state.BlockState ibd = cbd.getState(); + return adapt(ibd); + } + + public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) { + return BlockTypesCache.states[adaptToChar(blockState)]; + } + + public char adaptToChar(net.minecraft.world.level.block.state.BlockState blockState) { + int id = Block.BLOCK_STATE_REGISTRY.getId(blockState); + if (initialised) { + return ibdToStateOrdinal[id]; + } + synchronized (this) { + if (initialised) { + return ibdToStateOrdinal[id]; + } + try { + init(); + return ibdToStateOrdinal[id]; + } catch (ArrayIndexOutOfBoundsException e1) { + LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!", + blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1 + ); + return BlockTypesCache.ReservedIDs.AIR; + } + } + } + + public char ibdIDToOrdinal(int id) { + if (initialised) { + return ibdToStateOrdinal[id]; + } + synchronized (this) { + if (initialised) { + return ibdToStateOrdinal[id]; + } + init(); + return ibdToStateOrdinal[id]; + } + } + + @Override + public char[] getIbdToStateOrdinal() { + if (initialised) { + return ibdToStateOrdinal; + } + synchronized (this) { + if (initialised) { + return ibdToStateOrdinal; + } + init(); + return ibdToStateOrdinal; + } + } + + public int ordinalToIbdID(char ordinal) { + if (initialised) { + return ordinalToIbdID[ordinal]; + } + synchronized (this) { + if (initialised) { + return ordinalToIbdID[ordinal]; + } + init(); + return ordinalToIbdID[ordinal]; + } + } + + @Override + public int[] getOrdinalToIbdID() { + if (initialised) { + return ordinalToIbdID; + } + synchronized (this) { + if (initialised) { + return ordinalToIbdID; + } + init(); + return ordinalToIbdID; + } + } + + @Override + public > BlockData adapt(B state) { + PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); + return material.getCraftBlockData(); + } + + @Override + public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { + ServerLevel nmsWorld = getServerLevel(world); + ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); + if (map != null && wasAccessibleSinceLastSave(map)) { + boolean flag = false; + // PlayerChunk.d players = map.players; + Stream stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag) + */ Stream.empty(); + + ServerPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle(); + stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer) + .forEach(entityPlayer -> { + synchronized (chunkPacket) { + ClientboundLevelChunkWithLightPacket nmsPacket = (ClientboundLevelChunkWithLightPacket) chunkPacket.getNativePacket(); + if (nmsPacket == null) { + nmsPacket = mapUtil.create(this, chunkPacket); + chunkPacket.setNativePacket(nmsPacket); + } + try { + FaweCache.INSTANCE.CHUNK_FLAG.get().set(true); + entityPlayer.connection.send(nmsPacket); + } finally { + FaweCache.INSTANCE.CHUNK_FLAG.get().set(false); + } + } + }); + } + } + + @Override + public Map> getProperties(BlockType blockType) { + return getParent().getProperties(blockType); + } + + @Override + public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) { + int internalId = BlockStateIdAccess.getBlockStateId(blockState); + net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); + return blockState1.hasPostProcess( + getServerLevel(world), + new BlockPos(blockVector3.x(), blockVector3.y(), blockVector3.z()) + ); + } + + @Override + public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { + final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess(); + ItemStack stack = new ItemStack( + registryAccess.registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(baseItemStack.getType().id())), + baseItemStack.getAmount() + ); + final CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()); + if (nbt != null) { + final DataComponentPatch patch = COMPONENTS_CODEC + .parse(registryAccess.createSerializationContext(NbtOps.INSTANCE), nbt) + .getOrThrow(); + stack.applyComponents(patch); + } + return CraftItemStack.asCraftMirror(stack); + } + + @Override + protected void preCaptureStates(final ServerLevel serverLevel) { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + } + + @Override + protected List getCapturedBlockStatesCopy(final ServerLevel serverLevel) { + return new ArrayList<>(serverLevel.capturedBlockStates.values()); + } + + @Override + protected void postCaptureBlockStates(final ServerLevel serverLevel) { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + + @Override + protected ServerLevel getServerLevel(final World world) { + return ((CraftWorld) world).getHandle(); + } + + @Override + public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { + final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess(); + final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); + final net.minecraft.nbt.Tag tag = COMPONENTS_CODEC.encodeStart( + registryAccess.createSerializationContext(NbtOps.INSTANCE), + nmsStack.getComponentsPatch() + ).getOrThrow(); + return new BaseItemStack( + BukkitAdapter.asItemType(itemStack.getType()), + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)), + itemStack.getAmount() + ); + } + + @Override + public Tag toNative(net.minecraft.nbt.Tag foreign) { + return parent.toNative(foreign); + } + + @Override + public net.minecraft.nbt.Tag fromNative(Tag foreign) { + if (foreign instanceof PaperweightLazyCompoundTag) { + return ((PaperweightLazyCompoundTag) foreign).get(); + } + return parent.fromNative(foreign); + } + + @Override + public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { + return new PaperweightRegen(bukkitWorld, region, target, options).regenerate(); + } + + @Override + public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { + return new PaperweightGetBlocks(world, chunkX, chunkZ); + } + + @Override + public int getInternalBiomeId(BiomeType biomeType) { + final Registry registry = MinecraftServer + .getServer() + .registryAccess() + .registryOrThrow(BIOME); + ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.id()); + Biome biome = registry.get(resourceLocation); + return registry.getId(biome); + } + + @Override + public Iterable getRegisteredBiomes() { + WritableRegistry biomeRegistry = (WritableRegistry) ((CraftServer) Bukkit.getServer()) + .getServer() + .registryAccess() + .registryOrThrow(BIOME); + List keys = biomeRegistry.stream() + .map(biomeRegistry::getKey).filter(Objects::nonNull).toList(); + List namespacedKeys = new ArrayList<>(); + for (ResourceLocation key : keys) { + try { + namespacedKeys.add(CraftNamespacedKey.fromMinecraft(key)); + } catch (IllegalArgumentException e) { + LOGGER.error("Error converting biome key {}", key.toString(), e); + } + } + return namespacedKeys; + } + + @Override + public RelighterFactory getRelighterFactory() { + if (PaperLib.isPaper()) { + return new PaperweightStarlightRelighterFactory(); + } else { + return new NMSRelighterFactory(); + } + } + + @Override + public Map>> getAllProperties() { + if (initialised) { + return allBlockProperties; + } + synchronized (this) { + if (initialised) { + return allBlockProperties; + } + init(); + return allBlockProperties; + } + } + + @Override + public IBatchProcessor getTickingPostProcessor() { + return new PaperweightPostProcessor(); + } + + private boolean wasAccessibleSinceLastSave(ChunkHolder holder) { + if (!PaperLib.isPaper() || !PaperweightPlatformAdapter.POST_CHUNK_REWRITE) { + try { + return (boolean) CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE.invoke(holder); + } catch (IllegalAccessException | InvocationTargetException ignored) { + // fall-through + } + } + // Papers new chunk system has no related replacement - therefor we assume true. + return true; + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweWorldNativeAccess.java new file mode 100644 index 000000000..f7c2dc8e8 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweWorldNativeAccess.java @@ -0,0 +1,293 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; + +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.math.IntPair; +import com.fastasyncworldedit.core.util.TaskManager; +import com.fastasyncworldedit.core.util.task.RunnableVal; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.world.block.BlockState; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.FullChunkStatus; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.event.block.BlockPhysicsEvent; +import org.enginehub.linbus.tree.LinCompoundTag; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess { + + private static final int UPDATE = 1; + private static final int NOTIFY = 2; + private static final Direction[] NEIGHBOUR_ORDER = { + Direction.EAST, + Direction.WEST, + Direction.DOWN, + Direction.UP, + Direction.NORTH, + Direction.SOUTH + }; + private final PaperweightFaweAdapter paperweightFaweAdapter; + private final WeakReference level; + private final AtomicInteger lastTick; + private final Set cachedChanges = new HashSet<>(); + private final Set cachedChunksToSend = new HashSet<>(); + private SideEffectSet sideEffectSet; + + public PaperweightFaweWorldNativeAccess(PaperweightFaweAdapter paperweightFaweAdapter, WeakReference level) { + this.paperweightFaweAdapter = paperweightFaweAdapter; + this.level = level; + // Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging. + // - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway. + this.lastTick = new AtomicInteger(MinecraftServer.currentTick); + } + + private Level getLevel() { + return Objects.requireNonNull(level.get(), "The reference to the world was lost"); + } + + @Override + public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + @Override + public LevelChunk getChunk(int x, int z) { + return getLevel().getChunk(x, z); + } + + @Override + public net.minecraft.world.level.block.state.BlockState toNative(BlockState blockState) { + int stateId = paperweightFaweAdapter.ordinalToIbdID(blockState.getOrdinalChar()); + return BlockStateIdAccess.isValidInternalId(stateId) + ? Block.stateById(stateId) + : ((CraftBlockData) BukkitAdapter.adapt(blockState)).getState(); + } + + @Override + public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk levelChunk, BlockPos blockPos) { + return levelChunk.getBlockState(blockPos); + } + + @Nullable + @Override + public synchronized net.minecraft.world.level.block.state.BlockState setBlockState( + LevelChunk levelChunk, BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState blockState + ) { + int currentTick = MinecraftServer.currentTick; + if (Fawe.isMainThread()) { + return levelChunk.setBlockState(blockPos, blockState, + this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE) + ); + } + // Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( ) + cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState)); + cachedChunksToSend.add(new IntPair(levelChunk.locX, levelChunk.locZ)); + boolean nextTick = lastTick.get() > currentTick; + if (nextTick || cachedChanges.size() >= 1024) { + if (nextTick) { + lastTick.set(currentTick); + } + flushAsync(nextTick); + } + return blockState; + } + + @Override + public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition( + net.minecraft.world.level.block.state.BlockState blockState, + BlockPos blockPos + ) { + return Block.updateFromNeighbourShapes(blockState, getLevel(), blockPos); + } + + @Override + public BlockPos getPosition(int x, int y, int z) { + return new BlockPos(x, y, z); + } + + @Override + public void updateLightingForBlock(BlockPos blockPos) { + getLevel().getChunkSource().getLightEngine().checkBlock(blockPos); + } + + @Override + public boolean updateTileEntity(BlockPos blockPos, LinCompoundTag tag) { + // We will assume that the tile entity was created for us, + // though we do not do this on the other versions + BlockEntity blockEntity = getLevel().getBlockEntity(blockPos); + if (blockEntity == null) { + return false; + } + net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeLin(tag); + blockEntity.loadWithComponents((CompoundTag) nativeTag, DedicatedServer.getServer().registryAccess()); + return true; + } + + @Override + public void notifyBlockUpdate( + LevelChunk levelChunk, BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { + getLevel().sendBlockUpdated(blockPos, oldState, newState, UPDATE | NOTIFY); + } + } + + @Override + public boolean isChunkTicking(LevelChunk levelChunk) { + return levelChunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING); + } + + @Override + public void markBlockChanged(LevelChunk levelChunk, BlockPos blockPos) { + if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { + ((ServerChunkCache) getLevel().getChunkSource()).blockChanged(blockPos); + } + } + + @Override + public void notifyNeighbors( + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + Level level = getLevel(); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + level.blockUpdated(blockPos, oldState.getBlock()); + } else { + // When we don't want events, manually run the physics without them. + // Un-nest neighbour updating + for (Direction direction : NEIGHBOUR_ORDER) { + BlockPos shifted = blockPos.relative(direction); + level.getBlockState(shifted).handleNeighborChanged(level, shifted, oldState.getBlock(), blockPos, false); + } + } + if (newState.hasAnalogOutputSignal()) { + level.updateNeighbourForOutputSignal(blockPos, newState.getBlock()); + } + } + + @Override + public void updateNeighbors( + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState, + int recursionLimit + ) { + Level level = getLevel(); + // a == updateNeighbors + // b == updateDiagonalNeighbors + oldState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + CraftWorld craftWorld = level.getWorld(); + if (craftWorld != null) { + BlockPhysicsEvent event = new BlockPhysicsEvent( + craftWorld.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()), + CraftBlockData.fromData(newState) + ); + level.getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + } + } + newState.triggerEvent(level, blockPos, NOTIFY, recursionLimit); + newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); + } + + @Override + public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { + Level world = getLevel(); + newState.onPlace(world, pos, oldState, false); + } + + @Override + public void onBlockStateChange( + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + getLevel().onBlockStateChange(blockPos, oldState, newState); + } + + private synchronized void flushAsync(final boolean sendChunks) { + final Set changes = Set.copyOf(cachedChanges); + cachedChanges.clear(); + final Set toSend; + if (sendChunks) { + toSend = Set.copyOf(cachedChunksToSend); + cachedChunksToSend.clear(); + } else { + toSend = Collections.emptySet(); + } + RunnableVal runnableVal = new RunnableVal<>() { + @Override + public void run(Object value) { + changes.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, + sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) + )); + if (!sendChunks) { + return; + } + for (IntPair chunk : toSend) { + PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z()); + } + } + }; + TaskManager.taskManager().async(() -> TaskManager.taskManager().sync(runnableVal)); + } + + @Override + public synchronized void flush() { + RunnableVal runnableVal = new RunnableVal<>() { + @Override + public void run(Object value) { + cachedChanges.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, + sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) + )); + for (IntPair chunk : cachedChunksToSend) { + PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z()); + } + } + }; + if (Fawe.isMainThread()) { + runnableVal.run(); + } else { + TaskManager.taskManager().sync(runnableVal); + } + cachedChanges.clear(); + cachedChunksToSend.clear(); + } + + private record CachedChange( + LevelChunk levelChunk, + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState blockState + ) { + + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks.java new file mode 100644 index 000000000..bdd9d0648 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks.java @@ -0,0 +1,1186 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; + +import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; +import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import com.fastasyncworldedit.core.queue.implementation.QueueHandler; +import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; +import com.fastasyncworldedit.core.util.MathMan; +import com.fastasyncworldedit.core.util.collection.AdaptedMap; +import com.google.common.base.Suppliers; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import io.papermc.lib.PaperLib; +import io.papermc.paper.event.block.BeaconDeactivatedEvent; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.IdMap; +import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; +import net.minecraft.nbt.IntTag; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.util.BitStorage; +import net.minecraft.util.ZeroBitStorage; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.entity.BeaconBlockEntity; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.HashMapPalette; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.LinearPalette; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.apache.logging.log4j.Logger; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import javax.annotation.Nonnull; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Future; +import java.util.concurrent.Semaphore; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static net.minecraft.core.registries.Registries.BIOME; + +public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private static final Function posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); + private static final Function nmsTile2We = tileEntity -> new PaperweightLazyCompoundTag( + Suppliers.memoize(() -> tileEntity.saveWithId(DedicatedServer.getServer().registryAccess())) + ); + private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin + .getInstance() + .getBukkitImplAdapter()); + private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); + private final ReentrantLock callLock = new ReentrantLock(); + private final ServerLevel serverLevel; + private final int chunkX; + private final int chunkZ; + private final int minHeight; + private final int maxHeight; + private final int minSectionPosition; + private final int maxSectionPosition; + private final Registry biomeRegistry; + private final IdMap> biomeHolderIdMap; + private final ConcurrentHashMap copies = new ConcurrentHashMap<>(); + private final Object sendLock = new Object(); + private LevelChunkSection[] sections; + private LevelChunk levelChunk; + private DataLayer[] blockLight; + private DataLayer[] skyLight; + private boolean createCopy = false; + private boolean forceLoadSections = true; + private boolean lightUpdate = false; + private int copyKey = 0; + + public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { + this(((CraftWorld) world).getHandle(), chunkX, chunkZ); + } + + public PaperweightGetBlocks(ServerLevel serverLevel, int chunkX, int chunkZ) { + super(serverLevel.getMinBuildHeight() >> 4, (serverLevel.getMaxBuildHeight() - 1) >> 4); + this.serverLevel = serverLevel; + this.chunkX = chunkX; + this.chunkZ = chunkZ; + this.minHeight = serverLevel.getMinBuildHeight(); + this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. + this.minSectionPosition = minHeight >> 4; + this.maxSectionPosition = maxHeight >> 4; + this.skyLight = new DataLayer[getSectionCount()]; + this.blockLight = new DataLayer[getSectionCount()]; + this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME); + this.biomeHolderIdMap = biomeRegistry.asHolderIdMap(); + } + + public int getChunkX() { + return chunkX; + } + + public int getChunkZ() { + return chunkZ; + } + + @Override + public boolean isCreateCopy() { + return createCopy; + } + + @Override + public int setCreateCopy(boolean createCopy) { + if (!callLock.isHeldByCurrentThread()) { + throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); + } + this.createCopy = createCopy; + // Increment regardless of whether copy will be created or not to return null from getCopy() + return ++this.copyKey; + } + + @Override + public IChunkGet getCopy(final int key) { + return copies.remove(key); + } + + @Override + public void lockCall() { + this.callLock.lock(); + } + + @Override + public void unlockCall() { + this.callLock.unlock(); + } + + @Override + public void setLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { + if (light != null) { + lightUpdate = true; + try { + fillLightNibble(light, LightLayer.BLOCK, minSectionPosition, maxSectionPosition); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + @Override + public void setSkyLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { + if (light != null) { + lightUpdate = true; + try { + fillLightNibble(light, LightLayer.SKY, minSectionPosition, maxSectionPosition); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + @Override + public void setHeightmapToGet(HeightMapType type, int[] data) { + // height + 1 to match server internal + BitArrayUnstretched bitArray = new BitArrayUnstretched(MathMan.log2nlz(getChunk().getHeight() + 1), 256); + bitArray.fromRaw(data); + Heightmap.Types nativeType = Heightmap.Types.valueOf(type.name()); + Heightmap heightMap = getChunk().heightmaps.get(nativeType); + heightMap.setRawData(getChunk(), nativeType, bitArray.getData()); + } + + @Override + public int getMaxY() { + return maxHeight; + } + + @Override + public int getMinY() { + return minHeight; + } + + @Override + public BiomeType getBiomeType(int x, int y, int z) { + LevelChunkSection section = getSections(false)[(y >> 4) - getMinSectionPosition()]; + Holder biomes = section.getNoiseBiome(x >> 2, (y & 15) >> 2, z >> 2); + return PaperweightPlatformAdapter.adapt(biomes, serverLevel); + } + + @Override + public void removeSectionLighting(int layer, boolean sky) { + SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.BLOCK).getDataLayerData( + sectionPos); + if (dataLayer != null) { + lightUpdate = true; + synchronized (dataLayer) { + byte[] bytes = dataLayer.getData(); + Arrays.fill(bytes, (byte) 0); + } + } + if (sky) { + SectionPos sectionPos1 = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer1 = serverLevel + .getChunkSource() + .getLightEngine() + .getLayerListener(LightLayer.SKY) + .getDataLayerData(sectionPos1); + if (dataLayer1 != null) { + lightUpdate = true; + synchronized (dataLayer1) { + byte[] bytes = dataLayer1.getData(); + Arrays.fill(bytes, (byte) 0); + } + } + } + } + + @Override + public CompoundTag getTile(int x, int y, int z) { + BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( + chunkX << 4), y, (z & 15) + ( + chunkZ << 4))); + if (blockEntity == null) { + return null; + } + return new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()))); + } + + @Override + public Map getTiles() { + Map nmsTiles = getChunk().getBlockEntities(); + if (nmsTiles.isEmpty()) { + return Collections.emptyMap(); + } + return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); + } + + @Override + public int getSkyLight(int x, int y, int z) { + int layer = y >> 4; + int alayer = layer - getMinSectionPosition(); + if (skyLight[alayer] == null) { + SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer = + serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.SKY).getDataLayerData(sectionPos); + // If the server hasn't generated the section's NibbleArray yet, it will be null + if (dataLayer == null) { + byte[] LAYER_COUNT = new byte[2048]; + // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. + Arrays.fill(LAYER_COUNT, (byte) 15); + dataLayer = new DataLayer(LAYER_COUNT); + ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( + LightLayer.BLOCK, + sectionPos, + dataLayer + ); + } + skyLight[alayer] = dataLayer; + } + return skyLight[alayer].get(x & 15, y & 15, z & 15); + } + + @Override + public int getEmittedLight(int x, int y, int z) { + int layer = y >> 4; + int alayer = layer - getMinSectionPosition(); + if (blockLight[alayer] == null) { + serverLevel.getRawBrightness(new BlockPos(1, 1, 1), 5); + SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer = serverLevel + .getChunkSource() + .getLightEngine() + .getLayerListener(LightLayer.BLOCK) + .getDataLayerData(sectionPos); + // If the server hasn't generated the section's DataLayer yet, it will be null + if (dataLayer == null) { + byte[] LAYER_COUNT = new byte[2048]; + // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. + Arrays.fill(LAYER_COUNT, (byte) 15); + dataLayer = new DataLayer(LAYER_COUNT); + ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos, + dataLayer + ); + } + blockLight[alayer] = dataLayer; + } + return blockLight[alayer].get(x & 15, y & 15, z & 15); + } + + @Override + public int[] getHeightMap(HeightMapType type) { + long[] longArray = getChunk().heightmaps.get(Heightmap.Types.valueOf(type.name())).getRawData(); + BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256, longArray); + return bitArray.toRaw(new int[256]); + } + + @Override + public CompoundTag getEntity(UUID uuid) { + ensureLoaded(serverLevel, chunkX, chunkZ); + List entities = PaperweightPlatformAdapter.getEntities(getChunk()); + Entity entity = null; + for (Entity e : entities) { + if (e.getUUID().equals(uuid)) { + entity = e; + break; + } + } + if (entity != null) { + org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); + return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); + } + for (CompoundTag tag : getEntities()) { + if (uuid.equals(tag.getUUID())) { + return tag; + } + } + return null; + } + + @Override + public Set getEntities() { + ensureLoaded(serverLevel, chunkX, chunkZ); + List entities = PaperweightPlatformAdapter.getEntities(getChunk()); + if (entities.isEmpty()) { + return Collections.emptySet(); + } + int size = entities.size(); + return new AbstractSet<>() { + @Override + public int size() { + return size; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean contains(Object get) { + if (!(get instanceof CompoundTag getTag)) { + return false; + } + UUID getUUID = getTag.getUUID(); + for (Entity entity : entities) { + UUID uuid = entity.getUUID(); + if (uuid.equals(getUUID)) { + return true; + } + } + return false; + } + + @Nonnull + @Override + public Iterator iterator() { + Iterable result = entities.stream().map(input -> { + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + input.save(tag); + return (CompoundTag) adapter.toNative(tag); + }).collect(Collectors.toList()); + return result.iterator(); + } + }; + } + + private void removeEntity(Entity entity) { + entity.discard(); + } + + public LevelChunk ensureLoaded(ServerLevel nmsWorld, int chunkX, int chunkZ) { + return PaperweightPlatformAdapter.ensureLoaded(nmsWorld, chunkX, chunkZ); + } + + @Override + @SuppressWarnings("rawtypes") + public synchronized > T call(IChunkSet set, Runnable finalizer) { + if (!callLock.isHeldByCurrentThread()) { + throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked."); + } + forceLoadSections = false; + PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + if (createCopy) { + if (copies.containsKey(copyKey)) { + throw new IllegalStateException("Copy key already used."); + } + copies.put(copyKey, copy); + } + try { + ServerLevel nmsWorld = serverLevel; + LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); + + // Remove existing tiles. Create a copy so that we can remove blocks + Map chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); + List beacons = null; + if (!chunkTiles.isEmpty()) { + for (Map.Entry entry : chunkTiles.entrySet()) { + final BlockPos pos = entry.getKey(); + final int lx = pos.getX() & 15; + final int ly = pos.getY(); + final int lz = pos.getZ() & 15; + final int layer = ly >> 4; + if (!set.hasSection(layer)) { + continue; + } + + int ordinal = set.getBlock(lx, ly, lz).getOrdinal(); + if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) { + BlockEntity tile = entry.getValue(); + if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) { + if (beacons == null) { + beacons = new ArrayList<>(); + } + beacons.add(tile); + PaperweightPlatformAdapter.removeBeacon(tile, nmsChunk); + continue; + } + nmsChunk.removeBlockEntity(tile.getBlockPos()); + if (createCopy) { + copy.storeTile(tile); + } + } + } + } + final BiomeType[][] biomes = set.getBiomes(); + + int bitMask = 0; + synchronized (nmsChunk) { + LevelChunkSection[] levelChunkSections = nmsChunk.getSections(); + + for (int layerNo = getMinSectionPosition(); layerNo <= getMaxSectionPosition(); layerNo++) { + + int getSectionIndex = layerNo - getMinSectionPosition(); + int setSectionIndex = layerNo - set.getMinSectionPosition(); + + if (!set.hasSection(layerNo)) { + // No blocks, but might be biomes present. Handle this lazily. + if (biomes == null) { + continue; + } + if (layerNo < set.getMinSectionPosition() || layerNo > set.getMaxSectionPosition()) { + continue; + } + if (biomes[setSectionIndex] != null) { + synchronized (super.sectionLocks[getSectionIndex]) { + LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; + if (createCopy && existingSection != null) { + copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); + } + + if (existingSection == null) { + PalettedContainer> biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer( + biomes[setSectionIndex], + biomeHolderIdMap + ); + LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + new char[4096], + adapter, + biomeRegistry, + biomeData + ); + if (PaperweightPlatformAdapter.setSectionAtomic( + levelChunkSections, + null, + newSection, + getSectionIndex + )) { + updateGet(nmsChunk, levelChunkSections, newSection, new char[4096], getSectionIndex); + continue; + } else { + existingSection = levelChunkSections[getSectionIndex]; + if (existingSection == null) { + LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, + getSectionIndex + ); + continue; + } + } + } else { + PalettedContainer> paletteBiomes = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); + if (paletteBiomes != null) { + PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes); + } + } + } + } + continue; + } + + bitMask |= 1 << getSectionIndex; + + // setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to + // this chunk GET when #updateGet is called. Future dords, please listen this time. + char[] tmp = set.load(layerNo); + char[] setArr = new char[tmp.length]; + System.arraycopy(tmp, 0, setArr, 0, tmp.length); + + // synchronise on internal section to avoid circular locking with a continuing edit if the chunk was + // submitted to keep loaded internal chunks to queue target size. + synchronized (super.sectionLocks[getSectionIndex]) { + + LevelChunkSection newSection; + LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; + // Don't attempt to tick section whilst we're editing + if (existingSection != null) { + PaperweightPlatformAdapter.clearCounts(existingSection); + } + + if (createCopy) { + char[] tmpLoad = loadPrivately(layerNo); + char[] copyArr = new char[4096]; + System.arraycopy(tmpLoad, 0, copyArr, 0, 4096); + copy.storeSection(getSectionIndex, copyArr); + if (biomes != null && existingSection != null) { + copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); + } + } + + if (existingSection == null) { + PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( + biomeHolderIdMap, + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), + PalettedContainer.Strategy.SECTION_BIOMES + ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + setArr, + adapter, + biomeRegistry, + biomeData + ); + if (PaperweightPlatformAdapter.setSectionAtomic( + levelChunkSections, + null, + newSection, + getSectionIndex + )) { + updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); + continue; + } else { + existingSection = levelChunkSections[getSectionIndex]; + if (existingSection == null) { + LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, + getSectionIndex + ); + continue; + } + } + } + + //ensure that the server doesn't try to tick the chunksection while we're editing it. (Again) + PaperweightPlatformAdapter.clearCounts(existingSection); + DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); + + // Synchronize to prevent further acquisitions + synchronized (lock) { + lock.acquire(); // Wait until we have the lock + lock.release(); + try { + sectionLock.writeLock().lock(); + if (this.getChunk() != nmsChunk) { + this.levelChunk = nmsChunk; + this.sections = null; + this.reset(); + } else if (existingSection != getSections(false)[getSectionIndex]) { + this.sections[getSectionIndex] = existingSection; + this.reset(); + } else if (!Arrays.equals( + update(getSectionIndex, new char[4096], true), + loadPrivately(layerNo) + )) { + this.reset(layerNo); + /*} else if (lock.isModified()) { + this.reset(layerNo);*/ + } + } finally { + sectionLock.writeLock().unlock(); + } + + PalettedContainer> biomeData = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); + + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + this::loadPrivately, + setArr, + adapter, + biomeRegistry, + biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() + ); + if (!PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, existingSection, + newSection, + getSectionIndex + )) { + LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, + getSectionIndex + ); + } else { + updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); + } + } + } + } + + Map heightMaps = set.getHeightMaps(); + for (Map.Entry entry : heightMaps.entrySet()) { + PaperweightGetBlocks.this.setHeightmapToGet(entry.getKey(), entry.getValue()); + } + PaperweightGetBlocks.this.setLightingToGet( + set.getLight(), + set.getMinSectionPosition(), + set.getMaxSectionPosition() + ); + PaperweightGetBlocks.this.setSkyLightingToGet( + set.getSkyLight(), + set.getMinSectionPosition(), + set.getMaxSectionPosition() + ); + + Runnable[] syncTasks = null; + + int bx = chunkX << 4; + int bz = chunkZ << 4; + + // Call beacon deactivate events here synchronously + // list will be null on spigot, so this is an implicit isPaper check + if (beacons != null && !beacons.isEmpty()) { + final List finalBeacons = beacons; + + syncTasks = new Runnable[4]; + + syncTasks[3] = () -> { + for (BlockEntity beacon : finalBeacons) { + BeaconBlockEntity.playSound(beacon.getLevel(), beacon.getBlockPos(), SoundEvents.BEACON_DEACTIVATE); + new BeaconDeactivatedEvent(CraftBlock.at(beacon.getLevel(), beacon.getBlockPos())).callEvent(); + } + }; + } + + Set entityRemoves = set.getEntityRemoves(); + if (entityRemoves != null && !entityRemoves.isEmpty()) { + if (syncTasks == null) { + syncTasks = new Runnable[3]; + } + + syncTasks[2] = () -> { + Set entitiesRemoved = new HashSet<>(); + final List entities = PaperweightPlatformAdapter.getEntities(nmsChunk); + + for (Entity entity : entities) { + UUID uuid = entity.getUUID(); + if (entityRemoves.contains(uuid)) { + if (createCopy) { + copy.storeEntity(entity); + } + removeEntity(entity); + entitiesRemoved.add(uuid); + entityRemoves.remove(uuid); + } + } + if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { + for (UUID uuid : entityRemoves) { + Entity entity = nmsWorld.getEntities().get(uuid); + if (entity != null) { + removeEntity(entity); + } + } + } + // Only save entities that were actually removed to history + set.getEntityRemoves().clear(); + set.getEntityRemoves().addAll(entitiesRemoved); + }; + } + + Set entities = set.getEntities(); + if (entities != null && !entities.isEmpty()) { + if (syncTasks == null) { + syncTasks = new Runnable[2]; + } + + syncTasks[1] = () -> { + Iterator iterator = entities.iterator(); + while (iterator.hasNext()) { + final CompoundTag nativeTag = iterator.next(); + final Map> entityTagMap = nativeTag.getValue(); + final StringTag idTag = (StringTag) entityTagMap.get("Id"); + final ListTag posTag = (ListTag) entityTagMap.get("Pos"); + final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); + if (idTag == null || posTag == null || rotTag == null) { + LOGGER.error("Unknown entity tag: {}", nativeTag); + continue; + } + final double x = posTag.getDouble(0); + final double y = posTag.getDouble(1); + final double z = posTag.getDouble(2); + final float yaw = rotTag.getFloat(0); + final float pitch = rotTag.getFloat(1); + final String id = idTag.getValue(); + + EntityType type = EntityType.byString(id).orElse(null); + if (type != null) { + Entity entity = type.create(nmsWorld); + if (entity != null) { + final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( + nativeTag); + for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + entity.load(tag); + entity.absMoveTo(x, y, z, yaw, pitch); + entity.setUUID(nativeTag.getUUID()); + if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { + LOGGER.warn( + "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", + id, + nmsWorld.getWorld().getName(), + x, + y, + z + ); + // Unsuccessful create should not be saved to history + iterator.remove(); + } + } + } + } + }; + } + + // set tiles + Map tiles = set.getTiles(); + if (tiles != null && !tiles.isEmpty()) { + if (syncTasks == null) { + syncTasks = new Runnable[1]; + } + + syncTasks[0] = () -> { + for (final Map.Entry entry : tiles.entrySet()) { + final CompoundTag nativeTag = entry.getValue(); + final BlockVector3 blockHash = entry.getKey(); + final int x = blockHash.x() + bx; + final int y = blockHash.y(); + final int z = blockHash.z() + bz; + final BlockPos pos = new BlockPos(x, y, z); + + synchronized (nmsWorld) { + BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); + if (tileEntity == null || tileEntity.isRemoved()) { + nmsWorld.removeBlockEntity(pos); + tileEntity = nmsWorld.getBlockEntity(pos); + } + if (tileEntity != null) { + final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( + nativeTag); + tag.put("x", IntTag.valueOf(x)); + tag.put("y", IntTag.valueOf(y)); + tag.put("z", IntTag.valueOf(z)); + tileEntity.loadWithComponents(tag, DedicatedServer.getServer().registryAccess()); + } + } + } + }; + } + + Runnable callback; + if (bitMask == 0 && biomes == null && !lightUpdate) { + callback = null; + } else { + int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; + boolean finalLightUpdate = lightUpdate; + callback = () -> { + // Set Modified + nmsChunk.setLightCorrect(true); // Set Modified + nmsChunk.mustNotSave = false; + nmsChunk.setUnsaved(true); + // send to player + if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING || finalMask == 0 && biomes != null) { + this.send(); + } + if (finalizer != null) { + finalizer.run(); + } + }; + } + if (syncTasks != null) { + QueueHandler queueHandler = Fawe.instance().getQueueHandler(); + Runnable[] finalSyncTasks = syncTasks; + + // Chain the sync tasks and the callback + Callable chain = () -> { + try { + // Run the sync tasks + for (Runnable task : finalSyncTasks) { + if (task != null) { + task.run(); + } + } + if (callback == null) { + if (finalizer != null) { + queueHandler.async(finalizer, null); + } + return null; + } else { + return queueHandler.async(callback, null); + } + } catch (Throwable e) { + e.printStackTrace(); + throw e; + } + }; + //noinspection unchecked - required at compile time + return (T) (Future) queueHandler.sync(chain); + } else { + if (callback == null) { + if (finalizer != null) { + finalizer.run(); + } + } else { + callback.run(); + } + } + } + return null; + } catch (Throwable e) { + e.printStackTrace(); + return null; + } finally { + forceLoadSections = true; + } + } + + private void updateGet( + LevelChunk nmsChunk, + LevelChunkSection[] chunkSections, + LevelChunkSection section, + char[] arr, + int layer + ) { + try { + sectionLock.writeLock().lock(); + if (this.getChunk() != nmsChunk) { + this.levelChunk = nmsChunk; + this.sections = new LevelChunkSection[chunkSections.length]; + System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); + this.reset(); + } + if (this.sections == null) { + this.sections = new LevelChunkSection[chunkSections.length]; + System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); + } + if (this.sections[layer] != section) { + // Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords + this.sections[layer] = new LevelChunkSection[]{section}.clone()[0]; + } + } finally { + sectionLock.writeLock().unlock(); + } + this.blocks[layer] = arr; + } + + private char[] loadPrivately(int layer) { + layer -= getMinSectionPosition(); + if (super.sections[layer] != null) { + synchronized (super.sectionLocks[layer]) { + if (super.sections[layer].isFull() && super.blocks[layer] != null) { + return super.blocks[layer]; + } + } + } + return PaperweightGetBlocks.this.update(layer, null, true); + } + + @Override + public void send() { + synchronized (sendLock) { + PaperweightPlatformAdapter.sendChunk(this, serverLevel, chunkX, chunkZ); + } + } + + /** + * Update a given (nullable) data array to the current data stored in the server's chunk, associated with this + * {@link PaperweightPlatformAdapter} instance. Not synchronised to the {@link PaperweightPlatformAdapter} instance as synchronisation + * is handled where necessary in the method, and should otherwise be handled correctly by this method's caller. + * + * @param layer layer index (0 may denote a negative layer in the world, e.g. at y=-32) + * @param data array to be updated/filled with data or null + * @param aggressive if the cached section array should be re-acquired. + * @return the given array to be filled with data, or a new array if null is given. + */ + @Override + @SuppressWarnings("unchecked") + public char[] update(int layer, char[] data, boolean aggressive) { + LevelChunkSection section = getSections(aggressive)[layer]; + // Section is null, return empty array + if (section == null) { + data = new char[4096]; + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); + return data; + } + if (data != null && data.length != 4096) { + data = new char[4096]; + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); + } + if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) { + data = new char[4096]; + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); + } + Semaphore lock = PaperweightPlatformAdapter.applyLock(section); + synchronized (lock) { + // Efficiently convert ChunkSection to raw data + try { + lock.acquire(); + + final PalettedContainer blocks = section.getStates(); + final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocks); + final BitStorage bits = (BitStorage) PaperweightPlatformAdapter.fieldStorage.get(dataObject); + + if (bits instanceof ZeroBitStorage) { + Arrays.fill(data, adapter.adaptToChar(blocks.get(0, 0, 0))); // get(int) is only public on paper + return data; + } + + final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get(dataObject); + + final int bitsPerEntry = bits.getBits(); + final long[] blockStates = bits.getRaw(); + + new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).toRaw(data); + + int num_palette; + if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { + num_palette = palette.getSize(); + } else { + // The section's palette is the global block palette. + for (int i = 0; i < 4096; i++) { + char paletteVal = data[i]; + char ordinal = adapter.ibdIDToOrdinal(paletteVal); + data[i] = ordinal; + } + return data; + } + + char[] paletteToOrdinal = FaweCache.INSTANCE.PALETTE_TO_BLOCK_CHAR.get(); + try { + if (num_palette != 1) { + for (int i = 0; i < num_palette; i++) { + char ordinal = ordinal(palette.valueFor(i), adapter); + paletteToOrdinal[i] = ordinal; + } + for (int i = 0; i < 4096; i++) { + char paletteVal = data[i]; + char val = paletteToOrdinal[paletteVal]; + if (val == Character.MAX_VALUE) { + val = ordinal(palette.valueFor(i), adapter); + paletteToOrdinal[i] = val; + } + data[i] = val; + } + } else { + char ordinal = ordinal(palette.valueFor(0), adapter); + Arrays.fill(data, ordinal); + } + } finally { + for (int i = 0; i < num_palette; i++) { + paletteToOrdinal[i] = Character.MAX_VALUE; + } + } + return data; + } catch (IllegalAccessException | InterruptedException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } finally { + lock.release(); + } + } + } + + private char ordinal(BlockState ibd, PaperweightFaweAdapter adapter) { + if (ibd == null) { + return BlockTypesCache.ReservedIDs.AIR; + } else { + return adapter.adaptToChar(ibd); + } + } + + public LevelChunkSection[] getSections(boolean force) { + force &= forceLoadSections; + LevelChunkSection[] tmp = sections; + if (tmp == null || force) { + try { + sectionLock.writeLock().lock(); + tmp = sections; + if (tmp == null || force) { + LevelChunkSection[] chunkSections = getChunk().getSections(); + tmp = new LevelChunkSection[chunkSections.length]; + System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length); + sections = tmp; + } + } finally { + sectionLock.writeLock().unlock(); + } + } + return tmp; + } + + public LevelChunk getChunk() { + LevelChunk levelChunk = this.levelChunk; + if (levelChunk == null) { + synchronized (this) { + levelChunk = this.levelChunk; + if (levelChunk == null) { + this.levelChunk = levelChunk = ensureLoaded(this.serverLevel, chunkX, chunkZ); + } + } + } + return levelChunk; + } + + private void fillLightNibble(char[][] light, LightLayer lightLayer, int minSectionPosition, int maxSectionPosition) { + for (int Y = 0; Y <= maxSectionPosition - minSectionPosition; Y++) { + if (light[Y] == null) { + continue; + } + SectionPos sectionPos = SectionPos.of(levelChunk.getPos(), Y + minSectionPosition); + DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(lightLayer).getDataLayerData( + sectionPos); + if (dataLayer == null) { + byte[] LAYER_COUNT = new byte[2048]; + Arrays.fill(LAYER_COUNT, lightLayer == LightLayer.SKY ? (byte) 15 : (byte) 0); + dataLayer = new DataLayer(LAYER_COUNT); + ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( + lightLayer, + sectionPos, + dataLayer + ); + } + synchronized (dataLayer) { + for (int x = 0; x < 16; x++) { + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + int i = y << 8 | z << 4 | x; + if (light[Y][i] < 16) { + dataLayer.set(x, y, z, light[Y][i]); + } + } + } + } + } + } + } + + private PalettedContainer> setBiomesToPalettedContainer( + final BiomeType[][] biomes, + final int sectionIndex, + final PalettedContainerRO> data + ) { + BiomeType[] sectionBiomes; + if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { + return null; + } + PalettedContainer> biomeData = data.recreate(); + for (int y = 0, index = 0; y < 4; y++) { + for (int z = 0; z < 4; z++) { + for (int x = 0; x < 4; x++, index++) { + BiomeType biomeType = sectionBiomes[index]; + if (biomeType == null) { + biomeData.set(x, y, z, data.get(x, y, z)); + } else { + biomeData.set( + x, + y, + z, + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) + ); + } + } + } + } + return biomeData; + } + + @Override + public boolean hasSection(int layer) { + layer -= getMinSectionPosition(); + return getSections(false)[layer] != null; + } + + @Override + @SuppressWarnings("unchecked") + public synchronized boolean trim(boolean aggressive) { + skyLight = new DataLayer[getSectionCount()]; + blockLight = new DataLayer[getSectionCount()]; + if (aggressive) { + sectionLock.writeLock().lock(); + sections = null; + levelChunk = null; + sectionLock.writeLock().unlock(); + return super.trim(true); + } else if (sections == null) { + // don't bother trimming if there are no sections stored. + return true; + } else { + for (int i = getMinSectionPosition(); i <= getMaxSectionPosition(); i++) { + int layer = i - getMinSectionPosition(); + if (!hasSection(i) || !super.sections[layer].isFull()) { + continue; + } + LevelChunkSection existing = getSections(true)[layer]; + try { + final PalettedContainer blocksExisting = existing.getStates(); + + final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocksExisting); + final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get( + dataObject); + int paletteSize; + + if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { + paletteSize = palette.getSize(); + } else { + super.trim(false, i); + continue; + } + if (paletteSize == 1) { + //If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks. + continue; + } + super.trim(false, i); + } catch (IllegalAccessException ignored) { + super.trim(false, i); + } + } + return true; + } + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks_Copy.java new file mode 100644 index 000000000..a0a4d02d9 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks_Copy.java @@ -0,0 +1,260 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; + +import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.queue.IBlocks; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import com.google.common.base.Suppliers; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.BlockVector3; +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.BlockTypesCache; +import net.minecraft.core.Holder; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import org.apache.logging.log4j.Logger; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Future; + +public class PaperweightGetBlocks_Copy implements IChunkGet { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private final Map tiles = new HashMap<>(); + private final Set entities = new HashSet<>(); + private final char[][] blocks; + private final int minHeight; + private final int maxHeight; + final ServerLevel serverLevel; + final LevelChunk levelChunk; + private Holder[][] biomes = null; + + protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { + this.levelChunk = levelChunk; + this.serverLevel = levelChunk.level; + this.minHeight = serverLevel.getMinBuildHeight(); + this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. + this.blocks = new char[getSectionCount()][]; + } + + protected void storeTile(BlockEntity blockEntity) { + tiles.put( + BlockVector3.at( + blockEntity.getBlockPos().getX(), + blockEntity.getBlockPos().getY(), + blockEntity.getBlockPos().getZ() + ), + new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()))) + ); + } + + @Override + public Map getTiles() { + return tiles; + } + + @Override + @Nullable + public CompoundTag getTile(int x, int y, int z) { + return tiles.get(BlockVector3.at(x, y, z)); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + protected void storeEntity(Entity entity) { + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); + entity.save(compoundTag); + entities.add((CompoundTag) adapter.toNative(compoundTag)); + } + + @Override + public Set getEntities() { + return this.entities; + } + + @Override + public CompoundTag getEntity(UUID uuid) { + for (CompoundTag tag : entities) { + if (uuid.equals(tag.getUUID())) { + return tag; + } + } + return null; + } + + @Override + public boolean isCreateCopy() { + return false; + } + + @Override + public int setCreateCopy(boolean createCopy) { + return -1; + } + + @Override + public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { + } + + @Override + public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { + } + + @Override + public void setHeightmapToGet(HeightMapType type, int[] data) { + } + + @Override + public int getMaxY() { + return maxHeight; + } + + @Override + public int getMinY() { + return minHeight; + } + + @Override + public int getMaxSectionPosition() { + return maxHeight >> 4; + } + + @Override + public int getMinSectionPosition() { + return minHeight >> 4; + } + + @Override + public BiomeType getBiomeType(int x, int y, int z) { + Holder biome = biomes[(y >> 4) - getMinSectionPosition()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2]; + return PaperweightPlatformAdapter.adapt(biome, serverLevel); + } + + @Override + public void removeSectionLighting(int layer, boolean sky) { + } + + @Override + public boolean trim(boolean aggressive, int layer) { + return false; + } + + @Override + public IBlocks reset() { + return null; + } + + @Override + public int getSectionCount() { + return serverLevel.getSectionsCount(); + } + + protected void storeSection(int layer, char[] data) { + blocks[layer] = data; + } + + protected void storeBiomes(int layer, PalettedContainerRO> biomeData) { + if (biomes == null) { + biomes = new Holder[getSectionCount()][]; + } + if (biomes[layer] == null) { + biomes[layer] = new Holder[64]; + } + if (biomeData instanceof PalettedContainer> palettedContainer) { + for (int i = 0; i < 64; i++) { + biomes[layer][i] = palettedContainer.get(i); + } + } else { + LOGGER.error( + "Cannot correctly save biomes to history. Expected class type {} but got {}", + PalettedContainer.class.getSimpleName(), + biomeData.getClass().getSimpleName() + ); + } + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + BlockState state = BlockTypesCache.states[get(x, y, z)]; + return state.toBaseBlock(this, x, y, z); + } + + @Override + public boolean hasSection(int layer) { + layer -= getMinSectionPosition(); + return blocks[layer] != null; + } + + @Override + public char[] load(int layer) { + layer -= getMinSectionPosition(); + if (blocks[layer] == null) { + blocks[layer] = new char[4096]; + Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR); + } + return blocks[layer]; + } + + @Override + public char[] loadIfPresent(int layer) { + layer -= getMinSectionPosition(); + return blocks[layer]; + } + + @Override + public BlockState getBlock(int x, int y, int z) { + return BlockTypesCache.states[get(x, y, z)]; + } + + @Override + public int getSkyLight(int x, int y, int z) { + return 0; + } + + @Override + public int getEmittedLight(int x, int y, int z) { + return 0; + } + + @Override + public int[] getHeightMap(HeightMapType type) { + return new int[0]; + } + + @Override + public > T call(IChunkSet set, Runnable finalize) { + return null; + } + + public char get(int x, int y, int z) { + final int layer = (y >> 4) - getMinSectionPosition(); + final int index = (y & 15) << 8 | z << 4 | x; + return blocks[layer][index]; + } + + + @Override + public boolean trim(boolean aggressive) { + return false; + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightMapChunkUtil.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightMapChunkUtil.java new file mode 100644 index 000000000..6819e5466 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightMapChunkUtil.java @@ -0,0 +1,34 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; + +import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; + +//TODO un-very-break-this +public class PaperweightMapChunkUtil extends MapChunkUtil { + + public PaperweightMapChunkUtil() throws NoSuchFieldException { + fieldX = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("TWO_MEGABYTES", "a")); + fieldZ = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("x", "b")); + fieldBitMask = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("z", "c")); + fieldHeightMap = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("heightmaps", "b")); + fieldChunkData = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("chunkData", "d")); + fieldBlockEntities = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("buffer", "c")); + fieldFull = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("blockEntitiesData", "d")); + fieldX.setAccessible(true); + fieldZ.setAccessible(true); + fieldBitMask.setAccessible(true); + fieldHeightMap.setAccessible(true); + fieldChunkData.setAccessible(true); + fieldBlockEntities.setAccessible(true); + fieldFull.setAccessible(true); + } + + @Override + public ClientboundLevelChunkWithLightPacket createPacket() { + // TODO ??? return new ClientboundLevelChunkPacket(); + throw new UnsupportedOperationException(); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java new file mode 100644 index 000000000..33c7a8597 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java @@ -0,0 +1,727 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; + +import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices; +import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager; +import com.destroystokyo.paper.util.maplist.EntityList; +import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; +import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; +import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.util.MathMan; +import com.fastasyncworldedit.core.util.ReflectionUtils; +import com.fastasyncworldedit.core.util.TaskManager; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +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.BlockTypesCache; +import io.papermc.lib.PaperLib; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.IdMap; +import net.minecraft.core.Registry; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.BitStorage; +import net.minecraft.util.ExceptionCollector; +import net.minecraft.util.SimpleBitStorage; +import net.minecraft.util.ThreadingDetector; +import net.minecraft.util.Unit; +import net.minecraft.util.ZeroBitStorage; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.GlobalPalette; +import net.minecraft.world.level.chunk.HashMapPalette; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.LinearPalette; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.SingleValuePalette; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import org.apache.logging.log4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.CraftChunk; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Function; + +import static java.lang.invoke.MethodType.methodType; +import static net.minecraft.core.registries.Registries.BIOME; + +public final class PaperweightPlatformAdapter extends NMSAdapter { + + public static final Field fieldData; + + public static final Constructor dataConstructor; + + public static final Field fieldStorage; + public static final Field fieldPalette; + + private static final Field fieldTickingFluidCount; + private static final Field fieldTickingBlockCount; + private static final Field fieldBiomes; + + private static final MethodHandle methodGetVisibleChunk; + + private static final Field fieldThreadingDetector; + private static final Field fieldLock; + + private static final MethodHandle methodRemoveGameEventListener; + private static final MethodHandle methodremoveTickingBlockEntity; + + /* + * This is a workaround for the changes from https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/1fddefce1cdce44010927b888432bf70c0e88cde#src/main/java/org/bukkit/craftbukkit/CraftChunk.java + * and is only needed to support 1.19.4 versions before *and* after this change. + */ + private static final MethodHandle CRAFT_CHUNK_GET_HANDLE; + + private static final Field fieldRemove; + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + static final boolean POST_CHUNK_REWRITE; + private static Method PAPER_CHUNK_GEN_ALL_ENTITIES; + private static Field LEVEL_CHUNK_ENTITIES; + private static Field SERVER_LEVEL_ENTITY_MANAGER; + + static { + final MethodHandles.Lookup lookup = MethodHandles.lookup(); + try { + fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d")); + fieldData.setAccessible(true); + + Class dataClazz = fieldData.getType(); + dataConstructor = dataClazz.getDeclaredConstructors()[0]; + dataConstructor.setAccessible(true); + + fieldStorage = dataClazz.getDeclaredField(Refraction.pickName("storage", "b")); + fieldStorage.setAccessible(true); + fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c")); + fieldPalette.setAccessible(true); + + fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "g")); + fieldTickingFluidCount.setAccessible(true); + fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); + fieldTickingBlockCount.setAccessible(true); + fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i")); + fieldBiomes.setAccessible(true); + + Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( + "getVisibleChunkIfPresent", + "b" + ), long.class); + getVisibleChunkIfPresent.setAccessible(true); + methodGetVisibleChunk = lookup.unreflect(getVisibleChunkIfPresent); + + if (!PaperLib.isPaper()) { + fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); + fieldThreadingDetector.setAccessible(true); + fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); + fieldLock.setAccessible(true); + } else { + // in paper, the used methods are synchronized properly + fieldThreadingDetector = null; + fieldLock = null; + } + + Method removeGameEventListener = LevelChunk.class.getDeclaredMethod( + Refraction.pickName("removeGameEventListener", "a"), + BlockEntity.class, + ServerLevel.class + ); + removeGameEventListener.setAccessible(true); + methodRemoveGameEventListener = lookup.unreflect(removeGameEventListener); + + Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod( + Refraction.pickName( + "removeBlockEntityTicker", + "k" + ), BlockPos.class + ); + removeBlockEntityTicker.setAccessible(true); + methodremoveTickingBlockEntity = lookup.unreflect(removeBlockEntityTicker); + + fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p")); + fieldRemove.setAccessible(true); + + boolean chunkRewrite; + try { + Level.class.getDeclaredMethod("moonrise$getEntityLookup"); + chunkRewrite = true; + PAPER_CHUNK_GEN_ALL_ENTITIES = ChunkEntitySlices.class.getDeclaredMethod("getAllEntities"); + PAPER_CHUNK_GEN_ALL_ENTITIES.setAccessible(true); + } catch (NoSuchMethodException ignored) { + chunkRewrite = false; + } + try { + // Paper - Pre-Chunk-Update + LEVEL_CHUNK_ENTITIES = LevelChunk.class.getDeclaredField("entities"); + LEVEL_CHUNK_ENTITIES.setAccessible(true); + } catch (NoSuchFieldException ignored) { + } + try { + // Non-Paper + SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "N")); + SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true); + } catch (NoSuchFieldException ignored) { + } + POST_CHUNK_REWRITE = chunkRewrite; + } catch (RuntimeException | Error e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + MethodHandle craftChunkGetHandle; + final MethodType type = methodType(LevelChunk.class); + try { + craftChunkGetHandle = lookup.findVirtual(CraftChunk.class, "getHandle", type); + } catch (NoSuchMethodException | IllegalAccessException e) { + try { + final MethodType newType = methodType(ChunkAccess.class, ChunkStatus.class); + craftChunkGetHandle = lookup.findVirtual(CraftChunk.class, "getHandle", newType); + craftChunkGetHandle = MethodHandles.insertArguments(craftChunkGetHandle, 1, ChunkStatus.FULL); + } catch (NoSuchMethodException | IllegalAccessException ex) { + throw new RuntimeException(ex); + } + } + CRAFT_CHUNK_GET_HANDLE = craftChunkGetHandle; + } + + static boolean setSectionAtomic( + LevelChunkSection[] sections, + LevelChunkSection expected, + LevelChunkSection value, + int layer + ) { + if (layer >= 0 && layer < sections.length) { + return ReflectionUtils.compareAndSet(sections, expected, value, layer); + } + return false; + } + + // There is no point in having a functional semaphore for paper servers. + private static final ThreadLocal SEMAPHORE_THREAD_LOCAL = + ThreadLocal.withInitial(() -> new DelegateSemaphore(1, null)); + + static DelegateSemaphore applyLock(LevelChunkSection section) { + if (PaperLib.isPaper()) { + return SEMAPHORE_THREAD_LOCAL.get(); + } + try { + synchronized (section) { + PalettedContainer blocks = section.getStates(); + ThreadingDetector currentThreadingDetector = (ThreadingDetector) fieldThreadingDetector.get(blocks); + synchronized (currentThreadingDetector) { + Semaphore currentLock = (Semaphore) fieldLock.get(currentThreadingDetector); + if (currentLock instanceof DelegateSemaphore delegateSemaphore) { + return delegateSemaphore; + } + DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); + fieldLock.set(currentThreadingDetector, newLock); + return newLock; + } + } + } catch (Throwable e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) { + if (!PaperLib.isPaper()) { + LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false); + if (nmsChunk != null) { + return nmsChunk; + } + if (Fawe.isMainThread()) { + return serverLevel.getChunk(chunkX, chunkZ); + } + } else { + LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ); + if (nmsChunk != null) { + addTicket(serverLevel, chunkX, chunkZ); + return nmsChunk; + } + nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ); + if (nmsChunk != null) { + addTicket(serverLevel, chunkX, chunkZ); + return nmsChunk; + } + // Avoid "async" methods from the main thread. + if (Fawe.isMainThread()) { + return serverLevel.getChunk(chunkX, chunkZ); + } + CompletableFuture future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true); + try { + CraftChunk chunk; + try { + chunk = (CraftChunk) future.get(10, TimeUnit.SECONDS); + } catch (TimeoutException e) { + String world = serverLevel.getWorld().getName(); + // We've already taken 10 seconds we can afford to wait a little here. + boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null); + if (loaded) { + LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world); + // Retry chunk load + chunk = (CraftChunk) serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true).get(); + } else { + throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!"); + } + } + addTicket(serverLevel, chunkX, chunkZ); + return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk); + } catch (Throwable e) { + e.printStackTrace(); + } + } + return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)); + } + + private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) { + // Ensure chunk is definitely loaded before applying a ticket + io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel + .getChunkSource() + .addRegionTicket(ChunkHolderManager.UNLOAD_COOLDOWN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE)); + } + + public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) { + ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap; + try { + return (ChunkHolder) methodGetVisibleChunk.invoke(chunkMap, ChunkPos.asLong(chunkX, chunkZ)); + } catch (Throwable thr) { + throw new RuntimeException(thr); + } + } + + @SuppressWarnings("deprecation") + public static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int chunkZ) { + ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); + if (chunkHolder == null) { + return; + } + ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ); + LevelChunk levelChunk; + if (PaperLib.isPaper()) { + // getChunkAtIfLoadedImmediately is paper only + levelChunk = nmsWorld + .getChunkSource() + .getChunkAtIfLoadedImmediately(chunkX, chunkZ); + } else { + levelChunk = chunkHolder.getTickingChunkFuture() + .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).orElse(null); + } + if (levelChunk == null) { + return; + } + MinecraftServer.getServer().execute(() -> { + ClientboundLevelChunkWithLightPacket packet; + if (PaperLib.isPaper()) { + synchronized (chunk) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); + } + } else { + synchronized (chunk) { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); + } + } + nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); + }); + } + + private static List nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) { + return serverLevel.getChunkSource().chunkMap.getPlayers(coordIntPair, false); + } + + /* + NMS conversion + */ + public static LevelChunkSection newChunkSection( + final int layer, + final char[] blocks, + CachedBukkitAdapter adapter, + Registry biomeRegistry, + @Nullable PalettedContainer> biomes + ) { + return newChunkSection(layer, null, blocks, adapter, biomeRegistry, biomes); + } + + public static LevelChunkSection newChunkSection( + final int layer, + final Function get, + char[] set, + CachedBukkitAdapter adapter, + Registry biomeRegistry, + @Nullable PalettedContainer> biomes + ) { + if (set == null) { + return newChunkSection(biomeRegistry, biomes); + } + final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); + final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); + final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get(); + final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get(); + try { + int num_palette; + if (get == null) { + num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter, null); + } else { + num_palette = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, get, set, adapter, null); + } + + int bitsPerEntry = MathMan.log2nlz(num_palette - 1); + if (bitsPerEntry > 0 && bitsPerEntry < 5) { + bitsPerEntry = 4; + } else if (bitsPerEntry > 8) { + bitsPerEntry = MathMan.log2nlz(Block.BLOCK_STATE_REGISTRY.size() - 1); + } + + int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes + final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); + final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong); + + if (num_palette == 1) { + for (int i = 0; i < blockBitArrayEnd; i++) { + blockStates[i] = 0; + } + } else { + final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntryNonZero, 4096, blockStates); + bitArray.fromRaw(blocksCopy); + } + + final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd); + final BitStorage nmsBits; + if (bitsPerEntry == 0) { + nmsBits = new ZeroBitStorage(4096); + } else { + nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits); + } + List palette; + if (bitsPerEntry < 9) { + palette = new ArrayList<>(); + for (int i = 0; i < num_palette; i++) { + int ordinal = paletteToBlock[i]; + blockToPalette[ordinal] = Integer.MAX_VALUE; + final BlockState state = BlockTypesCache.states[ordinal]; + palette.add(((PaperweightBlockMaterial) state.getMaterial()).getState()); + } + } else { + palette = List.of(); + } + + // Create palette with data + @SuppressWarnings("deprecation") // constructor is deprecated on paper, but needed to keep compatibility with spigot + final PalettedContainer blockStatePalettedContainer = + new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, + PalettedContainer.Strategy.SECTION_STATES, + PalettedContainer.Strategy.SECTION_STATES.getConfiguration(Block.BLOCK_STATE_REGISTRY, bitsPerEntry), + nmsBits, + palette + ); + if (biomes == null) { + IdMap> biomeHolderIdMap = biomeRegistry.asHolderIdMap(); + biomes = new PalettedContainer<>( + biomeHolderIdMap, + biomeHolderIdMap.byIdOrThrow(WorldEditPlugin + .getInstance() + .getBukkitImplAdapter() + .getInternalBiomeId( + BiomeTypes.PLAINS)), + PalettedContainer.Strategy.SECTION_BIOMES + ); + } + + return new LevelChunkSection(blockStatePalettedContainer, biomes); + } catch (final Throwable e) { + throw e; + } finally { + Arrays.fill(blockToPalette, Integer.MAX_VALUE); + Arrays.fill(paletteToBlock, Integer.MAX_VALUE); + Arrays.fill(blockStates, 0); + Arrays.fill(blocksCopy, 0); + } + } + + @SuppressWarnings("deprecation") // Only deprecated in paper + private static LevelChunkSection newChunkSection( + Registry biomeRegistry, + @Nullable PalettedContainer> biomes + ) { + if (biomes == null) { + return new LevelChunkSection(biomeRegistry); + } + PalettedContainer dataPaletteBlocks = new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), + PalettedContainer.Strategy.SECTION_STATES + ); + return new LevelChunkSection(dataPaletteBlocks, biomes); + } + + public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer> biomes) { + try { + fieldBiomes.set(section, biomes); + } catch (IllegalAccessException e) { + LOGGER.error("Could not set biomes to chunk section", e); + } + } + + /** + * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. + */ + public static PalettedContainer> getBiomePalettedContainer( + BiomeType[] biomes, + IdMap> biomeRegistry + ) { + if (biomes == null) { + return null; + } + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + // Don't stream this as typically will see 1-4 biomes; stream overhead is large for the small length + Map> palette = new HashMap<>(); + for (BiomeType biomeType : new LinkedList<>(Arrays.asList(biomes))) { + Holder biome; + if (biomeType == null) { + biome = biomeRegistry.byId(adapter.getInternalBiomeId(BiomeTypes.PLAINS)); + } else { + biome = biomeRegistry.byId(adapter.getInternalBiomeId(biomeType)); + } + palette.put(biomeType, biome); + } + int biomeCount = palette.size(); + int bitsPerEntry = MathMan.log2nlz(biomeCount - 1); + Object configuration = PalettedContainer.Strategy.SECTION_STATES.getConfiguration( + new FakeIdMapBiome(biomeCount), + bitsPerEntry + ); + if (bitsPerEntry > 3) { + bitsPerEntry = MathMan.log2nlz(biomeRegistry.size() - 1); + } + PalettedContainer> biomePalettedContainer = new PalettedContainer<>( + biomeRegistry, + biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), + PalettedContainer.Strategy.SECTION_BIOMES + ); + + final Palette> biomePalette; + if (bitsPerEntry == 0) { + biomePalette = new SingleValuePalette<>( + biomePalettedContainer.registry, + biomePalettedContainer, + new ArrayList<>(palette.values()) // Must be modifiable + ); + } else if (bitsPerEntry == 4) { + biomePalette = LinearPalette.create( + 4, + biomePalettedContainer.registry, + biomePalettedContainer, + new ArrayList<>(palette.values()) // Must be modifiable + ); + } else if (bitsPerEntry < 9) { + biomePalette = HashMapPalette.create( + bitsPerEntry, + biomePalettedContainer.registry, + biomePalettedContainer, + new ArrayList<>(palette.values()) // Must be modifiable + ); + } else { + biomePalette = GlobalPalette.create( + bitsPerEntry, + biomePalettedContainer.registry, + biomePalettedContainer, + null // unused + ); + } + + int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes + final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); + final int arrayLength = MathMan.ceilZero(64f / blocksPerLong); + + + BitStorage bitStorage = bitsPerEntry == 0 ? new ZeroBitStorage(64) : new SimpleBitStorage( + bitsPerEntry, + 64, + new long[arrayLength] + ); + + try { + Object data = dataConstructor.newInstance(configuration, bitStorage, biomePalette); + fieldData.set(biomePalettedContainer, data); + int index = 0; + for (int y = 0; y < 4; y++) { + for (int z = 0; z < 4; z++) { + for (int x = 0; x < 4; x++, index++) { + BiomeType biomeType = biomes[index]; + if (biomeType == null) { + continue; + } + Holder biome = biomeRegistry.byId(WorldEditPlugin + .getInstance() + .getBukkitImplAdapter() + .getInternalBiomeId(biomeType)); + if (biome == null) { + continue; + } + biomePalettedContainer.set(x, y, z, biome); + } + } + } + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + return biomePalettedContainer; + } + + public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException { + fieldTickingFluidCount.setShort(section, (short) 0); + fieldTickingBlockCount.setShort(section, (short) 0); + } + + public static BiomeType adapt(Holder biome, LevelAccessor levelAccessor) { + final Registry biomeRegistry = levelAccessor.registryAccess().registryOrThrow(BIOME); + if (biomeRegistry.getKey(biome.value()) == null) { + return biomeRegistry.asHolderIdMap().getId(biome) == -1 ? BiomeTypes.OCEAN + : null; + } + return BiomeTypes.get(biome.unwrapKey().orElseThrow().location().toString()); + } + + static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { + try { + if (levelChunk.loaded || levelChunk.level.isClientSide()) { + BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos()); + if (blockEntity != null) { + if (!levelChunk.level.isClientSide) { + methodRemoveGameEventListener.invoke(levelChunk, beacon, levelChunk.level); + } + fieldRemove.set(beacon, true); + } + } + methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos()); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + + static List getEntities(LevelChunk chunk) { + ExceptionCollector collector = new ExceptionCollector<>(); + if (PaperLib.isPaper()) { + if (POST_CHUNK_REWRITE) { + try { + //noinspection unchecked + return (List) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level.moonrise$getEntityLookup().getChunk(chunk.locX, chunk.locZ)); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=true]", e); + } + } + try { + EntityList entityList = (EntityList) LEVEL_CHUNK_ENTITIES.get(chunk); + return List.of(entityList.getRawData()); + } catch (IllegalAccessException e) { + collector.add(new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=false]", e)); + // fall through + } + } + try { + //noinspection unchecked + return ((PersistentEntitySectionManager) (SERVER_LEVEL_ENTITY_MANAGER.get(chunk.level))).getEntities(chunk.getPos()); + } catch (IllegalAccessException e) { + collector.add(new RuntimeException("Failed to lookup entities [PAPER=false]", e)); + } + collector.throwIfPresent(); + return List.of(); + } + + record FakeIdMapBlock(int size) implements IdMap { + + @Override + public int getId(final net.minecraft.world.level.block.state.BlockState entry) { + return 0; + } + + @Nullable + @Override + public net.minecraft.world.level.block.state.BlockState byId(final int index) { + return null; + } + + @Nonnull + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + + } + + record FakeIdMapBiome(int size) implements IdMap { + + @Override + public int getId(final Biome entry) { + return 0; + } + + @Nullable + @Override + public Biome byId(final int index) { + return null; + } + + @Nonnull + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPostProcessor.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPostProcessor.java new file mode 100644 index 000000000..3b4c47087 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPostProcessor.java @@ -0,0 +1,175 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; + +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.extent.processor.ProcessorScope; +import com.fastasyncworldedit.core.queue.IBatchProcessor; +import com.fastasyncworldedit.core.queue.IChunk; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import com.fastasyncworldedit.core.registry.state.PropertyKey; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.Fluids; + +import javax.annotation.Nullable; + +public class PaperweightPostProcessor implements IBatchProcessor { + + @Override + public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) { + return set; + } + + @SuppressWarnings("deprecation") + @Override + public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) { + boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS; + // The PostProcessor shouldn't be added, but just in case + if (!tickFluid) { + return; + } + PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet; + layer: + for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) { + char[] set = iChunkSet.loadIfPresent(layer); + if (set == null) { + // No edit means no need to process + continue; + } + char[] get = null; + for (int i = 0; i < 4096; i++) { + char ordinal = set[i]; + char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__; + boolean fromGet = false; // Used for liquids + if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { + if (get == null) { + get = getBlocks.load(layer); + } + // If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't + // actually being set + if (get == null) { + continue layer; + } + fromGet = true; + ordinal = replacedOrdinal = get[i]; + } + if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { + continue; + } else if (!fromGet) { // if fromGet, don't do the same again + if (get == null) { + get = getBlocks.load(layer); + } + replacedOrdinal = get[i]; + } + boolean ticking = BlockTypesCache.ticking[ordinal]; + boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal]; + boolean replacedWasLiquid = false; + BlockState replacedState = null; + if (!ticking) { + // If the block being replaced was not ticking, it cannot be a liquid + if (!replacedWasTicking) { + continue; + } + // If the block being replaced is not fluid, we do not need to worry + if (!(replacedWasLiquid = + (replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) { + continue; + } + } + BlockState state = BlockState.getFromOrdinal(ordinal); + boolean liquid = state.getMaterial().isLiquid(); + int x = i & 15; + int y = (i >> 8) & 15; + int z = (i >> 4) & 15; + BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z); + if (liquid || replacedWasLiquid) { + if (liquid) { + addFluid(getBlocks.serverLevel, state, position); + continue; + } + // If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this + // may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up + // being ticked anyway. We only need it to be "hit" once. + if (!wasAdjacentToWater(get, set, i, x, y, z)) { + continue; + } + addFluid(getBlocks.serverLevel, replacedState, position); + } + } + } + } + + @Nullable + @Override + public Extent construct(final Extent child) { + throw new UnsupportedOperationException("Processing only"); + } + + @Override + public ProcessorScope getScope() { + return ProcessorScope.READING_SET_BLOCKS; + } + + private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) { + if (set == null || get == null) { + return false; + } + char ordinal; + char reserved = BlockTypesCache.ReservedIDs.__RESERVED__; + if (x > 0 && set[i - 1] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) { + return true; + } + } + if (x < 15 && set[i + 1] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) { + return true; + } + } + if (z > 0 && set[i - 16] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) { + return true; + } + } + if (z < 15 && set[i + 16] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) { + return true; + } + } + if (y > 0 && set[i - 256] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) { + return true; + } + } + if (y < 15 && set[i + 256] != reserved) { + return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal); + } + return false; + } + + @SuppressWarnings("deprecation") + private boolean isFluid(char ordinal) { + return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid(); + } + + @SuppressWarnings("deprecation") + private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) { + Fluid type; + if (replacedState.getBlockType() == BlockTypes.LAVA) { + type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA; + } else { + type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER; + } + serverLevel.scheduleTick( + position, + type, + type.getTickDelay(serverLevel) + ); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightStarlightRelighter.java new file mode 100644 index 000000000..f9d06922e --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightStarlightRelighter.java @@ -0,0 +1,79 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; + +import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.queue.IQueueExtent; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.TicketType; +import net.minecraft.util.Unit; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.status.ChunkPyramid; +import net.minecraft.world.level.chunk.status.ChunkStatus; + +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.IntConsumer; + +public class PaperweightStarlightRelighter extends StarlightRelighter { + + private static final TicketType FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); + private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkPyramid.LOADING_PYRAMID + .getStepTo(ChunkStatus.FULL) + .getAccumulatedRadiusOf(ChunkStatus.LIGHT); + + public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { + super(serverLevel, queue); + } + + @Override + protected ChunkPos createChunkPos(final long chunkKey) { + return new ChunkPos(chunkKey); + } + + @Override + protected long asLong(final int chunkX, final int chunkZ) { + return ChunkPos.asLong(chunkX, chunkZ); + } + + @Override + protected CompletableFuture chunkLoadFuture(final ChunkPos chunkPos) { + return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z) + .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( + FAWE_TICKET, + chunkPos, + LIGHT_LEVEL, + Unit.INSTANCE + )); + } + + protected void invokeRelight( + Set coords, + Consumer chunkCallback, + IntConsumer processCallback + ) { + try { + serverLevel.getChunkSource().getLightEngine().starlight$serverRelightChunks(coords, chunkCallback, processCallback); + } catch (Exception e) { + LOGGER.error("Error occurred on relighting", e); + } + } + + /* + * Allow the server to unload the chunks again. + * Also, if chunk packets are sent delayed, we need to do that here + */ + protected void postProcessChunks(Set coords) { + boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING; + for (ChunkPos pos : coords) { + int x = pos.x; + int z = pos.z; + if (delay) { // we still need to send the block changes of that chunk + PaperweightPlatformAdapter.sendChunk(pos, serverLevel, x, z); + } + serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE); + } + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightStarlightRelighterFactory.java new file mode 100644 index 000000000..beaffc9a6 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightStarlightRelighterFactory.java @@ -0,0 +1,25 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; + +import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; +import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; +import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; +import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; +import com.fastasyncworldedit.core.queue.IQueueExtent; +import com.sk89q.worldedit.world.World; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.CraftWorld; + +import javax.annotation.Nonnull; + +public class PaperweightStarlightRelighterFactory implements RelighterFactory { + + @Override + public @Nonnull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { + org.bukkit.World w = Bukkit.getWorld(world.getName()); + if (w == null) { + return NullRelighter.INSTANCE; + } + return new PaperweightStarlightRelighter(((CraftWorld) w).getHandle(), queue); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/nbt/PaperweightLazyCompoundTag.java new file mode 100644 index 000000000..e2ed21584 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/nbt/PaperweightLazyCompoundTag.java @@ -0,0 +1,161 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.nbt; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.LazyCompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import net.minecraft.nbt.NumericTag; +import org.enginehub.linbus.tree.LinCompoundTag; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +public class PaperweightLazyCompoundTag extends LazyCompoundTag { + + private final Supplier compoundTagSupplier; + private CompoundTag compoundTag; + + public PaperweightLazyCompoundTag(Supplier compoundTagSupplier) { + super(new HashMap<>()); + this.compoundTagSupplier = compoundTagSupplier; + } + + public PaperweightLazyCompoundTag(net.minecraft.nbt.CompoundTag compoundTag) { + this(() -> compoundTag); + } + + public net.minecraft.nbt.CompoundTag get() { + return compoundTagSupplier.get(); + } + + @Override + @SuppressWarnings("unchecked") + public Map> getValue() { + if (compoundTag == null) { + compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); + } + return compoundTag.getValue(); + } + + @Override + public LinCompoundTag toLinTag() { + getValue(); + return compoundTag.toLinTag(); + } + + public boolean containsKey(String key) { + return compoundTagSupplier.get().contains(key); + } + + public byte[] getByteArray(String key) { + return compoundTagSupplier.get().getByteArray(key); + } + + public byte getByte(String key) { + return compoundTagSupplier.get().getByte(key); + } + + public double getDouble(String key) { + return compoundTagSupplier.get().getDouble(key); + } + + public double asDouble(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof NumericTag numTag) { + return numTag.getAsDouble(); + } + return 0; + } + + public float getFloat(String key) { + return compoundTagSupplier.get().getFloat(key); + } + + public int[] getIntArray(String key) { + return compoundTagSupplier.get().getIntArray(key); + } + + public int getInt(String key) { + return compoundTagSupplier.get().getInt(key); + } + + public int asInt(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof NumericTag numTag) { + return numTag.getAsInt(); + } + return 0; + } + + @SuppressWarnings("unchecked") + public List> getList(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof net.minecraft.nbt.ListTag nbtList) { + ArrayList> list = new ArrayList<>(); + for (net.minecraft.nbt.Tag elem : nbtList) { + if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { + list.add(new PaperweightLazyCompoundTag(compoundTag)); + } else { + list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem)); + } + } + return list; + } + return Collections.emptyList(); + } + + @SuppressWarnings("unchecked") + public ListTag getListTag(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof net.minecraft.nbt.ListTag) { + return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag); + } + return new ListTag(StringTag.class, Collections.emptyList()); + } + + @SuppressWarnings("unchecked") + public > List getList(String key, Class listType) { + ListTag listTag = getListTag(key); + if (listTag.getType().equals(listType)) { + return (List) listTag.getValue(); + } else { + return Collections.emptyList(); + } + } + + public long[] getLongArray(String key) { + return compoundTagSupplier.get().getLongArray(key); + } + + public long getLong(String key) { + return compoundTagSupplier.get().getLong(key); + } + + public long asLong(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof NumericTag numTag) { + return numTag.getAsLong(); + } + return 0; + } + + public short getShort(String key) { + return compoundTagSupplier.get().getShort(key); + } + + public String getString(String key) { + return compoundTagSupplier.get().getString(key); + } + + @Override + public String toString() { + return compoundTagSupplier.get().toString(); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/regen/PaperweightRegen.java new file mode 100644 index 000000000..07933adfa --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/regen/PaperweightRegen.java @@ -0,0 +1,623 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.regen; + +import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager; +import com.fastasyncworldedit.bukkit.adapter.Regenerator; +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.queue.IChunkCache; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.util.TaskManager; +import com.google.common.collect.ImmutableList; +import com.mojang.serialization.Lifecycle; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.PaperweightGetBlocks; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.io.file.SafeFiles; +import com.sk89q.worldedit.world.RegenOptions; +import io.papermc.lib.PaperLib; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message; +import net.minecraft.server.level.GenerationChunkHolder; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.util.StaticCache2D; +import net.minecraft.util.thread.ProcessorHandle; +import net.minecraft.util.thread.ProcessorMailbox; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.LevelSettings; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.biome.FixedBiomeSource; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkPyramid; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.WorldGenContext; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.levelgen.WorldOptions; +import net.minecraft.world.level.levelgen.blending.BlendingData; +import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; +import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; +import net.minecraft.world.level.storage.LevelStorageSource; +import net.minecraft.world.level.storage.PrimaryLevelData; +import org.apache.logging.log4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; +import org.bukkit.generator.BiomeProvider; +import org.bukkit.generator.BlockPopulator; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nullable; +import java.lang.reflect.Field; +import java.nio.file.Path; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.OptionalLong; +import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.function.BooleanSupplier; +import java.util.function.Supplier; + +import static net.minecraft.core.registries.Registries.BIOME; + +public class PaperweightRegen extends Regenerator { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private static final Field serverWorldsField; + private static final Field paperConfigField; + private static final Field flatBedrockField; + private static final Field generatorSettingFlatField; + private static final Field generatorSettingBaseSupplierField; + private static final Field delegateField; + private static final Field chunkSourceField; + private static final Field generatorStructureStateField; + private static final Field ringPositionsField; + private static final Field hasGeneratedPositionsField; + + //list of chunk stati in correct order without FULL + private static final Map chunkStati = new LinkedHashMap<>(); + + static { + chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing + chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps + chunkStati.put( + ChunkStatus.STRUCTURE_REFERENCES, + Concurrency.NONE + ); // structure refs: radius 8, but only writes to current chunk + chunkStati.put(ChunkStatus.BIOMES, Concurrency.NONE); // biomes: radius 0 + chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8 + chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE + chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results + chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps + chunkStati.put( + ChunkStatus.INITIALIZE_LIGHT, + Concurrency.FULL + ); // initialize_light: radius 0 + chunkStati.put( + ChunkStatus.LIGHT, + Concurrency.FULL + ); // light: radius 1, but no writes to other chunks, only current chunk + chunkStati.put(ChunkStatus.SPAWN, Concurrency.NONE); // spawn: radius 0 + + try { + serverWorldsField = CraftServer.class.getDeclaredField("worlds"); + serverWorldsField.setAccessible(true); + + Field tmpPaperConfigField; + Field tmpFlatBedrockField; + try { //only present on paper + tmpPaperConfigField = Level.class.getDeclaredField("paperConfig"); + tmpPaperConfigField.setAccessible(true); + + tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock"); + tmpFlatBedrockField.setAccessible(true); + } catch (Exception e) { + tmpPaperConfigField = null; + tmpFlatBedrockField = null; + } + paperConfigField = tmpPaperConfigField; + flatBedrockField = tmpFlatBedrockField; + + generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName( + "settings", "e")); + generatorSettingBaseSupplierField.setAccessible(true); + + generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "d")); + generatorSettingFlatField.setAccessible(true); + + delegateField = CustomChunkGenerator.class.getDeclaredField("delegate"); + delegateField.setAccessible(true); + + chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "I")); + chunkSourceField.setAccessible(true); + + generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "w")); + generatorStructureStateField.setAccessible(true); + + ringPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(Refraction.pickName("ringPositions", "g")); + ringPositionsField.setAccessible(true); + + hasGeneratedPositionsField = ChunkGeneratorStructureState.class.getDeclaredField( + Refraction.pickName("hasGeneratedPositions", "h") + ); + hasGeneratedPositionsField.setAccessible(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + //runtime + private ServerLevel originalServerWorld; + private ServerChunkCache originalChunkProvider; + private ServerLevel freshWorld; + private ServerChunkCache freshChunkProvider; + private LevelStorageSource.LevelStorageAccess session; + private StructureTemplateManager structureTemplateManager; + private ThreadedLevelLightEngine threadedLevelLightEngine; + private ChunkGenerator chunkGenerator; + private WorldGenContext worldGenContext; + + private Path tempDir; + + private boolean generateFlatBedrock = false; + + public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) { + super(originalBukkitWorld, region, target, options); + if (PaperLib.isPaper()) { + throw new UnsupportedOperationException("Regeneration currently not support on Paper due to the new generation system"); + } + } + + @Override + protected boolean prepare() { + this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle(); + originalChunkProvider = originalServerWorld.getChunkSource(); + + //flat bedrock? (only on paper) + if (paperConfigField != null) { + try { + generateFlatBedrock = flatBedrockField.getBoolean(paperConfigField.get(originalServerWorld)); + } catch (Exception ignored) { + } + } + + seed = options.getSeed().orElse(originalServerWorld.getSeed()); + chunkStati.forEach((s, c) -> super.chunkStatuses.put(new ChunkStatusWrap(s), c)); + + return true; + } + + @Override + @SuppressWarnings("unchecked") + protected boolean initNewWorld() throws Exception { + //world folder + tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen"); + + //prepare for world init (see upstream implementation for reference) + org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment(); + org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator(); + LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir); + ResourceKey levelStemResourceKey = getWorldDimKey(environment); + session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey); + PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData; + + MinecraftServer server = originalServerWorld.getCraftServer().getServer(); + WorldOptions originalOpts = originalWorldData.worldGenOptions(); + WorldOptions newOpts = options.getSeed().isPresent() + ? originalOpts.withSeed(OptionalLong.of(seed)) + : originalOpts; + LevelSettings newWorldSettings = new LevelSettings( + "faweregentempworld", + originalWorldData.settings.gameType(), + originalWorldData.settings.hardcore(), + originalWorldData.settings.difficulty(), + originalWorldData.settings.allowCommands(), + originalWorldData.settings.gameRules(), + originalWorldData.settings.getDataConfiguration() + ); + + PrimaryLevelData.SpecialWorldProperty specialWorldProperty = + originalWorldData.isFlatWorld() + ? PrimaryLevelData.SpecialWorldProperty.FLAT + : originalWorldData.isDebugWorld() + ? PrimaryLevelData.SpecialWorldProperty.DEBUG + : PrimaryLevelData.SpecialWorldProperty.NONE; + PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable()); + + BiomeProvider biomeProvider = getBiomeProvider(); + + + //init world + freshWorld = Fawe.instance().getQueueHandler().sync((Supplier) () -> new ServerLevel( + server, + server.executor, + session, + newWorldData, + originalServerWorld.dimension(), + DedicatedServer.getServer().registryAccess().registry(Registries.LEVEL_STEM).orElseThrow() + .getOrThrow(levelStemResourceKey), + new RegenNoOpWorldLoadListener(), + originalServerWorld.isDebug(), + seed, + ImmutableList.of(), + false, + originalServerWorld.getRandomSequences(), + environment, + generator, + biomeProvider + ) { + + private final Holder singleBiome = options.hasBiomeType() ? DedicatedServer.getServer().registryAccess() + .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( + WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) + ) : null; + + @Override + public void tick(@NotNull BooleanSupplier shouldKeepTicking) { //no ticking + } + + @Override + public @NotNull Holder getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { + if (options.hasBiomeType()) { + return singleBiome; + } + return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome( + biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler() + ); + } + + }).get(); + freshWorld.noSave = true; + removeWorldFromWorldsMap(); + newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name + if (paperConfigField != null) { + paperConfigField.set(freshWorld, originalServerWorld.paperConfig()); + } + + ChunkGenerator originalGenerator = originalChunkProvider.getGenerator(); + if (originalGenerator instanceof FlatLevelSource flatLevelSource) { + FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings(); + chunkGenerator = new FlatLevelSource(generatorSettingFlat); + } else if (originalGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + Holder generatorSettingBaseSupplier = (Holder) + generatorSettingBaseSupplierField.get(noiseBasedChunkGenerator); + BiomeSource biomeSource; + if (options.hasBiomeType()) { + biomeSource = new FixedBiomeSource( + DedicatedServer.getServer().registryAccess() + .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( + WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) + ) + ); + } else { + biomeSource = originalGenerator.getBiomeSource(); + } + chunkGenerator = new NoiseBasedChunkGenerator( + biomeSource, + generatorSettingBaseSupplier + ); + } else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) { + chunkGenerator = customChunkGenerator.getDelegate(); + } else { + LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName()); + return false; + } + if (generator != null) { + chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator); + generateConcurrent = generator.isParallelCapable(); + } +// chunkGenerator.conf = freshWorld.spigotConfig; - Does not exist anymore, may need to be re-addressed + + freshChunkProvider = new ServerChunkCache( + freshWorld, + session, + server.getFixerUpper(), + server.getStructureManager(), + server.executor, + chunkGenerator, + freshWorld.spigotConfig.viewDistance, + freshWorld.spigotConfig.simulationDistance, + server.forceSynchronousWrites(), + new RegenNoOpWorldLoadListener(), + (chunkCoordIntPair, state) -> { + }, + () -> server.overworld().getDataStorage() + ) { + // redirect to LevelChunks created in #createChunks + @Override + public ChunkAccess getChunk(int x, int z, @NotNull ChunkStatus chunkstatus, boolean create) { + ChunkAccess chunkAccess = getChunkAt(x, z); + if (chunkAccess == null && create) { + chunkAccess = createChunk(getProtoChunkAt(x, z)); + } + return chunkAccess; + } + }; + + if (seed == originalOpts.seed() && !options.hasBiomeType()) { + // Optimisation for needless ring position calculation when the seed and biome is the same. + ChunkGeneratorStructureState state = (ChunkGeneratorStructureState) generatorStructureStateField.get( + originalChunkProvider.chunkMap); + boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(state); + if (hasGeneratedPositions) { + Map>> origPositions = + (Map>>) ringPositionsField.get(state); + Map>> copy = new Object2ObjectArrayMap<>( + origPositions); + ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get( + freshChunkProvider.chunkMap); + ringPositionsField.set(newState, copy); + hasGeneratedPositionsField.setBoolean(newState, true); + } + } + + + chunkSourceField.set(freshWorld, freshChunkProvider); + //let's start then + structureTemplateManager = server.getStructureManager(); + threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider); + + this.worldGenContext = new WorldGenContext( + freshWorld, + chunkGenerator, + structureTemplateManager, + threadedLevelLightEngine, + originalChunkProvider.chunkMap.worldGenContext.mainThreadMailBox() + ); + return true; + } + + @Override + protected void cleanup() { + try { + session.close(); + } catch (Exception ignored) { + } + + //shutdown chunk provider + try { + Fawe.instance().getQueueHandler().sync(() -> { + try { + freshChunkProvider.close(false); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } catch (Exception ignored) { + } + + //remove world from server + try { + Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap); + } catch (Exception ignored) { + } + + //delete directory + try { + SafeFiles.tryHardToDeleteDir(tempDir); + } catch (Exception ignored) { + } + } + + @Override + protected ProtoChunk createProtoChunk(int x, int z) { + return new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld, + this.freshWorld.registryAccess().registryOrThrow(BIOME), null + ); + } + + @Override + protected LevelChunk createChunk(ProtoChunk protoChunk) { + return new LevelChunk( + freshWorld, + protoChunk, + null // we don't want to add entities + ); + } + + @Override + protected ChunkStatusWrap getFullChunkStatus() { + return new ChunkStatusWrap(ChunkStatus.FULL); + } + + @Override + protected List getBlockPopulators() { + return originalServerWorld.getWorld().getPopulators(); + } + + @Override + protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) { + // BlockPopulator#populate has to be called synchronously for TileEntity access + TaskManager.taskManager().task(() -> { + final CraftWorld world = freshWorld.getWorld(); + final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ); + blockPopulator.populate(world, random, chunk); + }); + } + + @Override + protected IChunkCache initSourceQueueCache() { + return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) { + @Override + public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) { + return getChunkAt(x, z); + } + }; + } + + //util + @SuppressWarnings("unchecked") + private void removeWorldFromWorldsMap() { + try { + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); + map.remove("faweregentempworld"); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private ResourceKey getWorldDimKey(org.bukkit.World.Environment env) { + return switch (env) { + case NETHER -> LevelStem.NETHER; + case THE_END -> LevelStem.END; + default -> LevelStem.OVERWORLD; + }; + } + + private static class RegenNoOpWorldLoadListener implements ChunkProgressListener { + + private RegenNoOpWorldLoadListener() { + } + + @Override + public void updateSpawnPos(@NotNull ChunkPos spawnPos) { + } + + @Override + public void onStatusChange( + final @NotNull ChunkPos pos, + @org.jetbrains.annotations.Nullable final net.minecraft.world.level.chunk.status.ChunkStatus status + ) { + + } + + @Override + public void start() { + + } + + @Override + public void stop() { + } + + // TODO Paper only(?) @Override + public void setChunkRadius(int radius) { + } + + } + + private class FastProtoChunk extends ProtoChunk { + + public FastProtoChunk( + final ChunkPos pos, + final UpgradeData upgradeData, + final LevelHeightAccessor world, + final Registry biomeRegistry, + @Nullable final BlendingData blendingData + ) { + super(pos, upgradeData, world, biomeRegistry, blendingData); + } + + // avoid warning on paper + + @SuppressWarnings("unused") // compatibility with spigot + public boolean generateFlatBedrock() { + return generateFlatBedrock; + } + + // no one will ever see the entities! + @Override + public @NotNull List getEntities() { + return Collections.emptyList(); + } + + } + + protected class ChunkStatusWrap extends ChunkStatusWrapper { + + private final ChunkStatus chunkStatus; + + public ChunkStatusWrap(ChunkStatus chunkStatus) { + this.chunkStatus = chunkStatus; + } + + @Override + public int requiredNeighborChunkRadius() { + return ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.FULL).getAccumulatedRadiusOf(chunkStatus); + } + + @Override + public String name() { + return chunkStatus.toString(); + } + + @Override + public CompletableFuture processChunk(List accessibleChunks) { + ChunkAccess chunkAccess = accessibleChunks.get(accessibleChunks.size() / 2); + int chunkX = chunkAccess.getPos().x; + int chunkZ = chunkAccess.getPos().z; + getProtoChunkAt(chunkX, chunkZ); + StaticCache2D neighbours = StaticCache2D + .create( + chunkX, + chunkZ, + requiredNeighborChunkRadius(), + (final int nx, final int nz) -> new ChunkHolder(new ChunkPos(nx, nz), + ChunkHolderManager.MAX_TICKET_LEVEL, + freshWorld, + threadedLevelLightEngine, + null, + freshChunkProvider.chunkMap + ) + ); + return ChunkPyramid.GENERATION_PYRAMID.getStepTo(chunkStatus).apply( + worldGenContext, + neighbours, + chunkAccess + ); + } + + } + + /** + * A light engine that does nothing. As light is calculated after pasting anyway, we can avoid + * work this way. + */ + static class NoOpLightEngine extends ThreadedLevelLightEngine { + + private static final ProcessorMailbox MAILBOX = ProcessorMailbox.create(task -> { + }, "fawe-no-op"); + private static final ProcessorHandle> HANDLE = ProcessorHandle.of("fawe-no-op", m -> { + }); + + public NoOpLightEngine(final ServerChunkCache chunkProvider) { + super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE); + } + + @Override + public @NotNull CompletableFuture lightChunk(final @NotNull ChunkAccess chunk, final boolean excludeBlocks) { + return CompletableFuture.completedFuture(chunk); + } + + } + +} diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index 258d9b83e..088ab22a0 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -208,7 +208,7 @@ tasks { versionNumber.set("${project.version}") versionType.set("release") uploadFile.set(file("build/libs/${rootProject.name}-Bukkit-${project.version}.jar")) - gameVersions.addAll(listOf("1.20.6", "1.20.5", "1.20.3", "1.20.2", "1.20.1", "1.20", "1.19.4")) + gameVersions.addAll(listOf("1.21", "1.20.6", "1.20.5", "1.20.3", "1.20.2", "1.20.1", "1.20", "1.19.4")) loaders.addAll(listOf("paper", "spigot")) changelog.set("The changelog is available on GitHub: https://github.com/IntellectualSites/" + "FastAsyncWorldEdit/releases/tag/${project.version}") From 4590dcb00624c045001485b930364644e7245490 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 30 Jun 2024 08:51:05 +0000 Subject: [PATCH 302/466] Update auto.value to v1.11.0 (#2811) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b02ec474b..d3c7ef643 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -25,7 +25,7 @@ adventure = "4.17.0" adventure-bukkit = "4.3.3" checkerqual = "3.43.0" truezip = "6.8.4" -auto-value = "1.10.4" +auto-value = "1.11.0" findbugs = "3.0.2" rhino-runtime = "1.7.15" zstd-jni = "1.4.8-1" # Not latest as it can be difficult to obtain latest ZSTD libs From 1db7df2e2c51eb12b5637fecf5bb149016c15e8e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 30 Jun 2024 08:51:20 +0000 Subject: [PATCH 303/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.3.3 (#2809) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d3c7ef643..0b88f66c6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.3.2" +towny = "0.100.3.3" plotsquared = "7.3.8" # Third party From 270e1a82a73340babe16929f698ed79b0f8b0592 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 30 Jun 2024 08:51:37 +0000 Subject: [PATCH 304/466] Update dependency org.enginehub.lin-bus:lin-bus-bom to v0.1.2 (#2810) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0b88f66c6..8fb4a51eb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -40,7 +40,7 @@ paperlib = "1.0.8" paster = "1.1.6" vault = "1.7.1" serverlib = "2.3.6" -linbus = "0.1.0" +linbus = "0.1.2" ## Internal text-adapter = "3.0.6" text = "3.0.4" From e8d17fbcd9deec90562807d51765c5b44615cc23 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 30 Jun 2024 08:55:04 +0000 Subject: [PATCH 305/466] Update dependency org.checkerframework:checker-qual to v3.44.0 (#2813) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8fb4a51eb..5c82ca09d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.17.0" adventure-bukkit = "4.3.3" -checkerqual = "3.43.0" +checkerqual = "3.44.0" truezip = "6.8.4" auto-value = "1.11.0" findbugs = "3.0.2" From 04fb55d4911db5b47776cb1ca1094540ab9a8744 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 30 Jun 2024 09:00:41 +0000 Subject: [PATCH 306/466] Update dependency gradle to v8.8 (#2812) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23a4..a4413138c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From c82ab99a22440b0101f03aa281e7782e5ed7ddb4 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 30 Jun 2024 11:14:40 +0200 Subject: [PATCH 307/466] Release 2.11.0 Signed-off-by: Alexander Brandes --- build.gradle.kts | 4 ++-- .../core/configuration/Config.java | 2 +- .../core/function/mask/BlockMaskBuilder.java | 4 ++-- .../java/com/sk89q/worldedit/LocalSession.java | 6 +++--- .../java/com/sk89q/worldedit/WorldEdit.java | 10 +++++----- .../worldedit/command/ClipboardCommands.java | 2 +- .../history/change/BiomeChange3D.java | 6 +++--- .../worldedit/history/change/BlockChange.java | 6 +++--- .../internal/registry/AbstractFactory.java | 2 +- .../com/sk89q/worldedit/math/BlockVector2.java | 12 ++++++------ .../com/sk89q/worldedit/math/BlockVector3.java | 18 +++++++++--------- .../java/com/sk89q/worldedit/math/Vector2.java | 8 ++++---- .../java/com/sk89q/worldedit/math/Vector3.java | 12 ++++++------ .../com/sk89q/worldedit/registry/Keyed.java | 4 ++-- .../com/sk89q/worldedit/util/LocatedBlock.java | 4 ++-- .../sk89q/worldedit/world/biome/BiomeType.java | 4 ++-- .../worldedit/world/entity/EntityType.java | 4 ++-- .../sk89q/worldedit/world/fluid/FluidType.java | 4 ++-- .../worldedit/world/registry/ItemMaterial.java | 8 ++++---- 19 files changed, 60 insertions(+), 60 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 0f188deeb..14be0a0a2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.10.1") +var rootVersion by extra("2.11.0") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s-%s", rootVersion, buildNumber) +version = String.format("%s", rootVersion) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java index 1d6f8d146..880b4cdf7 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java @@ -224,7 +224,7 @@ public class Config { /** * Indicates that a field's default value should match another input if the config is otherwise already generated * - * @since TODO + * @since 2.11.0 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java index 33ea8e3f7..7ca60bdd1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java @@ -65,7 +65,7 @@ public class BlockMaskBuilder { /** * Create a new instance with a given {@link ParserContext} to use if parsing regex * - * @since TODO + * @since 2.11.0 */ public BlockMaskBuilder(ParserContext context) { this(new long[BlockTypes.size()][], context); @@ -79,7 +79,7 @@ public class BlockMaskBuilder { /** * Create a new instance with a given {@link ParserContext} to use if parsing regex * - * @since TODO + * @since 2.11.0 */ protected BlockMaskBuilder(long[][] bitSets, ParserContext context) { this.bitSets = bitSets; 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 be1740dc4..48e2a8078 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -1352,7 +1352,7 @@ public class LocalSession implements TextureHolder { * @param item the item type * @param tool the tool to set, which can be {@code null} * @throws InvalidToolBindException if the item can't be bound to that item - * @since TODO + * @since 2.11.0 */ public void setTool(BaseItem item, @Nullable Tool tool) throws InvalidToolBindException { if (item.getType().hasBlockType()) { @@ -1919,7 +1919,7 @@ public class LocalSession implements TextureHolder { * Get the preferred wand item for this user, or {@code null} to use the default * * @return item id of wand item, or {@code null} - * @since TODO + * @since 2.11.0 */ public BaseItem getWandBaseItem() { return wandItem == null ? null : new BaseItem(wandItem.getType(), wandItem.getNbtReference()); @@ -1929,7 +1929,7 @@ public class LocalSession implements TextureHolder { * Get the preferred navigation wand item for this user, or {@code null} to use the default * * @return item id of nav wand item, or {@code null} - * @since TODO + * @since 2.11.0 */ public BaseItem getNavWandBaseItem() { return navWandItem == null ? null : new BaseItem(navWandItem.getType(), navWandItem.getNbtReference()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java index 402310def..8fbf61436 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -468,7 +468,7 @@ public final class WorldEdit { /** * @deprecated Use {@link WorldEdit#checkMaxBrushRadius(Expression, Actor)} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public void checkMaxBrushRadius(Expression radius) throws MaxBrushRadiusException { double val = radius.evaluate(); checkArgument(val >= 0, "Radius must be a positive number."); @@ -485,7 +485,7 @@ public final class WorldEdit { * @param radius Radius to check * @param actor Actor to check for * @throws MaxRadiusException If given radius larger than allowed - * @since TODO + * @since 2.11.0 */ public void checkMaxRadius(double radius, Actor actor) { int max = actor.getLimit().MAX_RADIUS; @@ -500,7 +500,7 @@ public final class WorldEdit { * @param radius Radius to check * @param actor Actor to check for * @throws MaxRadiusException If given radius larger than allowed - * @since TODO + * @since 2.11.0 */ public void checkMaxBrushRadius(double radius, Actor actor) { int max = actor.getLimit().MAX_BRUSH_RADIUS; @@ -515,7 +515,7 @@ public final class WorldEdit { * @param expression Radius to check * @param actor Actor to check for * @throws BrushRadiusLimitException If given radius larger than allowed - * @since TODO + * @since 2.11.0 */ public void checkMaxBrushRadius(Expression expression, Actor actor) { double radius = expression.evaluate(); @@ -532,7 +532,7 @@ public final class WorldEdit { * @param position Position to check * @param extent Extent to check in * @throws OutsideWorldBoundsException If the position is outside the world height limits - * @since TODO + * @since 2.11.0 */ public void checkExtentHeightBounds(BlockVector3 position, Extent extent) { if (position.y() < extent.getMinY() || position.y() > extent.getMaxY()) { 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 8c0b69ec9..378449755 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 @@ -340,7 +340,7 @@ public class ClipboardCommands { aliases = {"/download"}, desc = "Downloads your clipboard through the configured web interface" ) - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") @CommandPermissions({"worldedit.clipboard.download"}) public void download( final Actor actor, diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java index 1106899f8..4bdbddb4d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java @@ -56,7 +56,7 @@ public record BiomeChange3D(BlockVector3 position, BiomeType previous, BiomeType * @return the position * @deprecated Use {@link #position()}. */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public BlockVector3 getPosition() { return position; } @@ -67,7 +67,7 @@ public record BiomeChange3D(BlockVector3 position, BiomeType previous, BiomeType * @return the previous biome * @deprecated Use {@link #previous()}. */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public BiomeType getPrevious() { return previous; } @@ -78,7 +78,7 @@ public record BiomeChange3D(BlockVector3 position, BiomeType previous, BiomeType * @return the current biome * @deprecated Use {@link #current()}. */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public BiomeType getCurrent() { return current; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java index 16fc50e0d..ecde7967f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java @@ -71,7 +71,7 @@ public record BlockChange(BlockVector3 position, BaseBlock previous, BaseBlock c * @return the position * @deprecated use {@link #position()} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public BlockVector3 getPosition() { return position; } @@ -82,7 +82,7 @@ public record BlockChange(BlockVector3 position, BaseBlock previous, BaseBlock c * @return the previous block * @deprecated use {@link #previous()} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public BaseBlock getPrevious() { return previous; } @@ -93,7 +93,7 @@ public record BlockChange(BlockVector3 position, BaseBlock previous, BaseBlock c * @return the current block * @deprecated use {@link #current()} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public BaseBlock getCurrent() { return current; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java index 0934627b9..75fae8ca2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java @@ -68,7 +68,7 @@ public abstract class AbstractFactory { * @param worldEdit the WorldEdit instance * @param defaultParser the parser to fall back to * @param richParser the rich parser - * @since TODO + * @since 2.11.0 */ protected AbstractFactory(WorldEdit worldEdit, InputParser defaultParser, FaweParser richParser) { checkNotNull(worldEdit); 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 baed5ffde..7db9cd7e2 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 @@ -122,7 +122,7 @@ public class BlockVector2 { * Get the X coordinate. * * @return the x coordinate - * @since TODO + * @since 2.11.0 */ public int x() { return x; @@ -134,7 +134,7 @@ public class BlockVector2 { * @return the x coordinate * @deprecated use {@link #x()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getX() { return x; } @@ -145,7 +145,7 @@ public class BlockVector2 { * @return the x coordinate * @deprecated use {@link #x()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getBlockX() { return x; } @@ -164,7 +164,7 @@ public class BlockVector2 { * Get the Z coordinate. * * @return the z coordinate - * @since TODO + * @since 2.11.0 */ public int z() { return z; @@ -176,7 +176,7 @@ public class BlockVector2 { * @return the z coordinate * @deprecated use {@link #z()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getZ() { return z; } @@ -187,7 +187,7 @@ public class BlockVector2 { * @return the z coordinate * @deprecated use {@link #z()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getBlockZ() { return 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 3d239b352..ee2789a33 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 @@ -174,7 +174,7 @@ public abstract class BlockVector3 { * Get the X coordinate. * * @return the x coordinate - * @since TODO + * @since 2.11.0 */ public abstract int x(); //FAWE end @@ -185,7 +185,7 @@ public abstract class BlockVector3 { * @return the x coordinate * @deprecated use {@link #x()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getX() { return this.x(); //FAWE - access abstract getter instead of local field } @@ -196,7 +196,7 @@ public abstract class BlockVector3 { * @return the x coordinate * @deprecated use {@link #x()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getBlockX() { return this.x(); //FAWE - access abstract getter instead of local field } @@ -219,7 +219,7 @@ public abstract class BlockVector3 { * Get the Y coordinate. * * @return the y coordinate - * @since TODO + * @since 2.11.0 */ public abstract int y(); //FAWE end @@ -230,7 +230,7 @@ public abstract class BlockVector3 { * @return the y coordinate * @deprecated use {@link #y()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getY() { return this.y(); //FAWE - access abstract getter instead of local field } @@ -241,7 +241,7 @@ public abstract class BlockVector3 { * @return the y coordinate * @deprecated use {@link #y()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getBlockY() { return this.y(); //FAWE - access abstract getter instead of local field } @@ -263,7 +263,7 @@ public abstract class BlockVector3 { * Get the Z coordinate. * * @return the Z coordinate - * @since TODO + * @since 2.11.0 */ public abstract int z(); //FAWE end @@ -274,7 +274,7 @@ public abstract class BlockVector3 { * @return the z coordinate * @deprecated use {@link #z()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getZ() { return this.z(); //FAWE - access abstract getter instead of local field } @@ -285,7 +285,7 @@ public abstract class BlockVector3 { * @return the z coordinate * @deprecated use {@link #z()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getBlockZ() { return this.z(); //FAWE - access abstract getter instead of local field } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector2.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector2.java index 9d08676f9..089ed62ca 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector2.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector2.java @@ -57,7 +57,7 @@ public record Vector2(double x, double z) { * @return the x coordinate * @deprecated use {@link #x()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public double getX() { return x; } @@ -66,7 +66,7 @@ public record Vector2(double x, double z) { * Get the X coordinate, aligned to the block grid. * * @return the block-aligned x coordinate - * @since TODO + * @since 2.11.0 */ public int blockX() { return MathMan.roundInt(x); @@ -86,7 +86,7 @@ public record Vector2(double x, double z) { * Get the Z coordinate, aligned to the block grid. * * @return the block-aligned z coordinate - * @since TODO + * @since 2.11.0 */ public int blockZ() { return MathMan.roundInt(z); @@ -98,7 +98,7 @@ public record Vector2(double x, double z) { * @return the z coordinate * @deprecated use {@link #z()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public double getZ() { return z; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector3.java index 898bb5241..3b359920b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector3.java @@ -160,7 +160,7 @@ public abstract class Vector3 { * Get the X coordinate. * * @return the x coordinate - * @since TODO + * @since 2.11.0 */ public abstract double x(); @@ -179,7 +179,7 @@ public abstract class Vector3 { * @return the x coordinate * @deprecated use {@link #x()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public double getX() { return this.x(); } @@ -201,7 +201,7 @@ public abstract class Vector3 { * Get the Y coordinate. * * @return the y coordinate - * @since TODO + * @since 2.11.0 */ public abstract double y(); @@ -220,7 +220,7 @@ public abstract class Vector3 { * @return the y coordinate * @deprecated use {@link #y()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public double getY() { return this.y(); } @@ -241,7 +241,7 @@ public abstract class Vector3 { * Get the Z coordinate. * * @return the z coordinate - * @since TODO + * @since 2.11.0 */ public abstract double z(); @@ -260,7 +260,7 @@ public abstract class Vector3 { * @return the z coordinate * @deprecated use {@link #z()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public double getZ() { return this.z(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java index b31e62d7f..dfce5f833 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java @@ -33,7 +33,7 @@ public interface Keyed { * @return an id * @deprecated Use {@link #id()} instead. */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") default String getId() { return id(); } @@ -43,7 +43,7 @@ public interface Keyed { * may have additional restrictions. * * @return an id - * @since TODO + * @since 2.11.0 */ @NonAbstractForCompatibility(delegateName = "getId", delegateParams = {}) default String id() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java index ff946e458..042f435e0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java @@ -40,7 +40,7 @@ public record LocatedBlock(BlockVector3 location, BaseBlock block) { * @return The location * @deprecated This class is now a record. Use {@link #location()} instead. */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public BlockVector3 getLocation() { return this.location; } @@ -51,7 +51,7 @@ public record LocatedBlock(BlockVector3 location, BaseBlock block) { * @return The block * @deprecated This class is now a record. Use {@link #block()} instead. */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public BaseBlock getBlock() { return this.block; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java index e7ec152a9..d49289093 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java @@ -47,7 +47,7 @@ public class BiomeType implements RegistryItem, Keyed, BiomePattern { * Gets the ID of this biome. * * @return The id - * @since TODO + * @since 2.11.0 */ @Override public String id() { @@ -78,7 +78,7 @@ public class BiomeType implements RegistryItem, Keyed, BiomePattern { * @return The id * @deprecated use {@link #id()} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") @Override public String getId() { return this.id; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java index 1faf3bc4c..aba23b636 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java @@ -45,7 +45,7 @@ public class EntityType implements RegistryItem, Keyed { * Gets the id of this entity type. * * @return the id - * @since TODO + * @since 2.11.0 */ public String id() { return this.id; @@ -57,7 +57,7 @@ public class EntityType implements RegistryItem, Keyed { * @return the id * @deprecated use {@link #id()} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") @Override public String getId() { return this.id; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java index 1642ed4e9..1b191f07f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java @@ -43,7 +43,7 @@ public class FluidType implements RegistryItem, Keyed { * Gets the ID of this block. * * @return The id - * @since TODO + * @since 2.11.0 */ public String id() { return this.id; @@ -55,7 +55,7 @@ public class FluidType implements RegistryItem, Keyed { * @return The id * @deprecated use {@link #id()} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") @Override public String getId() { return this.id; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java index db63b53a4..45071859c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java @@ -29,7 +29,7 @@ public interface ItemMaterial { * @return the maximum quantity * @deprecated Use {@link #maxStackSize()} instead. */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") default int getMaxStackSize() { return maxStackSize(); } @@ -38,7 +38,7 @@ public interface ItemMaterial { * Gets the the maximum quantity of this item that can be in a single stack. * * @return the maximum quantity - * @since TODO + * @since 2.11.0 */ @NonAbstractForCompatibility(delegateName = "getMaxStackSize", delegateParams = {}) default int maxStackSize() { @@ -52,7 +52,7 @@ public interface ItemMaterial { * @return the maximum damage, or 0 if not applicable * @deprecated Use {@link #maxDamage()} instead. */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") default int getMaxDamage() { return maxDamage(); } @@ -61,7 +61,7 @@ public interface ItemMaterial { * Gets the the maximum damage this item can take before being broken. * * @return the maximum damage, or 0 if not applicable - * @since TODO + * @since 2.11.0 */ @NonAbstractForCompatibility(delegateName = "getMaxDamage", delegateParams = {}) default int maxDamage() { From e3fde6cf82cf7194427320da6085292d609b55be Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 30 Jun 2024 11:27:51 +0200 Subject: [PATCH 308/466] Back to snapshot for development Signed-off-by: Alexander Brandes --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 14be0a0a2..4dd632c1d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.11.0") +var rootVersion by extra("2.11.1") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s", rootVersion) +version = String.format("%s-%s", rootVersion, buildNumber) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From d9e69cfd58f6626f060ab3f38fdc7436ea6049bd Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 30 Jun 2024 21:59:06 +0200 Subject: [PATCH 309/466] fix: do not bother with refraction for biomes/i field, this just fixes it now --- .../impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java index 33c7a8597..8c7da74fa 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java @@ -141,7 +141,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount.setAccessible(true); - fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i")); + Field tmpFieldBiomes; + try { + // Seems it's sometimes biomes and sometimes "i". Idk this is just easier than having to try to deal with it + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); // apparently unobf + } catch (NoSuchFieldException ignored) { + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i"); // apparently obf + } + fieldBiomes = tmpFieldBiomes; fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( From 15c60279585dac9752328f9beec0842186356c3a Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 1 Jul 2024 16:19:28 +0200 Subject: [PATCH 310/466] fix: override min/max pos methods from SimpleClipboard (#2803) - fixes #2800 --- .../core/extent/clipboard/ReadOnlyClipboard.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java index 4f7245d27..2edb9cb51 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java @@ -2,13 +2,10 @@ package com.fastasyncworldedit.core.extent.clipboard; import com.fastasyncworldedit.core.Fawe; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.NBTUtils; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.request.Request; @@ -18,9 +15,7 @@ import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nullable; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.UUID; import java.util.function.Supplier; @@ -77,6 +72,16 @@ public abstract class ReadOnlyClipboard extends SimpleClipboard { }; } + @Override + public BlockVector3 getMinimumPoint() { + return region.getMinimumPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return region.getMaximumPoint(); + } + @Override public Region getRegion() { return region; From a14bb7ed2cfdf2beda60ebc38f2f5a7bede6f64e Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Tue, 2 Jul 2024 18:51:11 +0100 Subject: [PATCH 311/466] fix: remove synchronisation on chunk GET when sending packet --- .../v1_19_R3/PaperweightPlatformAdapter.java | 36 +++++++++---------- .../v1_20_R2/PaperweightPlatformAdapter.java | 32 ++++++++--------- .../v1_20_R3/PaperweightPlatformAdapter.java | 32 ++++++++--------- .../v1_20_R4/PaperweightPlatformAdapter.java | 32 ++++++++--------- .../v1_21_R1/PaperweightPlatformAdapter.java | 32 ++++++++--------- 5 files changed, 72 insertions(+), 92 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java index 334289b08..aec3cfd24 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java @@ -350,27 +350,23 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - synchronized (chunk) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - true, - false // last false is to not bother with x-ray - ); - } + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + true, + false // last false is to not bother with x-ray + ); } else { - synchronized (chunk) { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - true - ); - } + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + true + ); } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java index 91dcfe24e..23f59e8bf 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java @@ -364,25 +364,21 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - synchronized (chunk) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - false // last false is to not bother with x-ray - ); - } + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); } else { - synchronized (chunk) { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); - } + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java index f2f78eb7d..b69f476d3 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java @@ -364,25 +364,21 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - synchronized (chunk) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - false // last false is to not bother with x-ray - ); - } + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); } else { - synchronized (chunk) { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); - } + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java index 6c0f72590..1389cdda3 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java @@ -353,25 +353,21 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - synchronized (chunk) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - false // last false is to not bother with x-ray - ); - } + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); } else { - synchronized (chunk) { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); - } + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java index 8c7da74fa..c2931d7ff 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java @@ -361,25 +361,21 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - synchronized (chunk) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - false // last false is to not bother with x-ray - ); - } + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); } else { - synchronized (chunk) { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); - } + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); From 75d9475cf77bd06932c775a626b50202068b2c6c Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Tue, 2 Jul 2024 19:33:35 +0100 Subject: [PATCH 312/466] Disable regen completely on 1.21 for now --- .../impl/fawe/v1_21_R1/PaperweightFaweAdapter.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java index e0dae1b2f..0a2fe6f60 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java @@ -18,7 +18,6 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.regen.PaperweightRegen; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.internal.block.BlockStateIdAccess; @@ -556,10 +555,10 @@ public final class PaperweightFaweAdapter extends FaweAdapter Date: Tue, 2 Jul 2024 20:34:02 +0200 Subject: [PATCH 313/466] Use isMovementBlocker() instead of isSolid() in heightmap calculation (#2822) --- .../core/extent/processor/heightmap/HeightMapType.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightMapType.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightMapType.java index d49644f24..cb5339737 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightMapType.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightMapType.java @@ -17,19 +17,19 @@ public enum HeightMapType { MOTION_BLOCKING { @Override public boolean includes(BlockState state) { - return state.getMaterial().isSolid() || HeightMapType.hasFluid(state); + return state.getMaterial().isMovementBlocker() || HeightMapType.hasFluid(state); } }, MOTION_BLOCKING_NO_LEAVES { @Override public boolean includes(BlockState state) { - return (state.getMaterial().isSolid() || HeightMapType.hasFluid(state)) && !HeightMapType.isLeaf(state); + return (state.getMaterial().isMovementBlocker() || HeightMapType.hasFluid(state)) && !HeightMapType.isLeaf(state); } }, OCEAN_FLOOR { @Override public boolean includes(BlockState state) { - return state.getMaterial().isSolid(); + return state.getMaterial().isMovementBlocker(); } }, WORLD_SURFACE { From c3bb567ea7da2087dfb2ca1507dc2d5c0d6174c7 Mon Sep 17 00:00:00 2001 From: Jordan Date: Tue, 2 Jul 2024 20:34:11 +0200 Subject: [PATCH 314/466] fix: switch to 3d where 2d biomes still remain in a couple of places (#2816) --- .../com/fastasyncworldedit/core/extent/FaweRegionExtent.java | 2 +- .../com/fastasyncworldedit/core/extent/TransformExtent.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java index 103dd8824..4f4cce126 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java @@ -101,7 +101,7 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc @Override public BiomeType getBiomeType(int x, int y, int z) { - if (!contains(x, z)) { + if (!contains(x, y, z)) { if (!limit.MAX_FAILS()) { WEManager.weManager().cancelEditSafe(this, FaweCache.OUTSIDE_REGION); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java index c424c0f8c..daa731d3c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java @@ -93,7 +93,7 @@ public class TransformExtent extends BlockTransformExtent { @Override public BiomeType getBiomeType(int x, int y, int z) { BlockVector3 p = getPos(x, y, z); - return super.getBiomeType(p.x(), y, p.z()); + return super.getBiomeType(p.x(), p.y(), p.z()); } @Override From b511e878a48e8b725af5ad8d6cc8cca39211d678 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Tue, 2 Jul 2024 19:46:03 +0100 Subject: [PATCH 315/466] chore: throw exception on 1.21 regen --- .../impl/fawe/v1_21_R1/PaperweightFaweAdapter.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java index 0a2fe6f60..757ba0e29 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java @@ -555,10 +555,10 @@ public final class PaperweightFaweAdapter extends FaweAdapter Date: Fri, 5 Jul 2024 15:05:55 +0200 Subject: [PATCH 316/466] fix: clone polyhedral region last triangle too if present (#2807) --- .../com/fastasyncworldedit/core/regions/PolyhedralRegion.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/PolyhedralRegion.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/PolyhedralRegion.java index a1471c9d8..675e8efb6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/PolyhedralRegion.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/PolyhedralRegion.java @@ -77,7 +77,7 @@ public class PolyhedralRegion extends AbstractRegion { minimumPoint = region.minimumPoint; maximumPoint = region.maximumPoint; centerAccum = region.centerAccum; - lastTriangle = region.lastTriangle; + lastTriangle = lastTriangle == null ? null : region.lastTriangle.clone(); } /** From 5341b06813f75ffbee767896288aa7c77d948bb9 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Fri, 5 Jul 2024 17:20:13 +0100 Subject: [PATCH 317/466] Apply hack-fix for biomes to 1.20.6 as well --- .../impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java index 1389cdda3..03eabc698 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java @@ -140,7 +140,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount.setAccessible(true); - fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i")); + Field tmpFieldBiomes; + try { + // Seems it's sometimes biomes and sometimes "i". Idk this is just easier than having to try to deal with it + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); // apparently unobf + } catch (NoSuchFieldException ignored) { + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i"); // apparently obf + } + fieldBiomes = tmpFieldBiomes; fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( From ef064cbccfb4d4d22e70d8f0f89af8fed8714fbe Mon Sep 17 00:00:00 2001 From: RadND <69626236+RadND@users.noreply.github.com> Date: Sun, 7 Jul 2024 21:16:39 +0800 Subject: [PATCH 318/466] Add worldedit.tool.none to fawe.permpack.basic (#2827) Add missing permission node in fawe.permpack.basic in bukkit If node "fawe.permpack.basic" exist in other platform than bukkit,this minor bug would exist here too,but i lack the knowledge of finding it out. --- worldedit-bukkit/src/main/resources/plugin.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/worldedit-bukkit/src/main/resources/plugin.yml b/worldedit-bukkit/src/main/resources/plugin.yml index cd12b1008..282587ce8 100644 --- a/worldedit-bukkit/src/main/resources/plugin.yml +++ b/worldedit-bukkit/src/main/resources/plugin.yml @@ -135,6 +135,7 @@ permissions: worldedit.brush.options.transform: true worldedit.brush.options.scroll: true worldedit.brush.options.visualize: true + worldedit.tool.none: true worldedit.tool.deltree: true worldedit.tool.farwand: true worldedit.tool.lrbuild: true From 1917406334ff39305639e94c740fe5c1d1377a8e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 02:12:18 +0000 Subject: [PATCH 319/466] Update dependency paperweight-userdev to v1.20.6-R0.1-20240702.153951-123 (#2830) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts index 34e3569eb..1512dca87 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/ - the().paperDevBundle("1.20.6-R0.1-20240617.192752-122") + the().paperDevBundle("1.20.6-R0.1-20240702.153951-123") compileOnly(libs.paperlib) } From 514da16d193ac26154d795e4f77a6b688da085e3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 02:12:58 +0000 Subject: [PATCH 320/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.3.4 (#2829) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5c82ca09d..48f436e07 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.3.3" +towny = "0.100.3.4" plotsquared = "7.3.8" # Third party From 1ec87e7092d9bddf246713e49efc1e3036af1257 Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Sat, 13 Jul 2024 14:30:34 +0200 Subject: [PATCH 321/466] Support Sponge Schematic v3 (#2776) * Update to Sponge Schematic 3 Includes a major refactoring of how schematics are read. (cherry picked from commit bd475b1d4acbcf2a95e5a8f3aee50d2fb2100ae8) * Licenses lol (cherry picked from commit a5ce8a47657aa987da8ca625cd658856d2eb3477) * Fix imports (cherry picked from commit e1892b7bd4ff0ca4592f8cb4e1b2d9363c4cd6ff) * Update for final changes (cherry picked from commit 2f6b50a4276b33b615d9dbc52e73e958308735f9) * chore: ensure flushed clipboard in spongev2 writer * feat: initial work on FastSchematicWriterV2 * fix: only write into palette once, write into data as varint * chore: more work on FastSchematicWriterV3 * fix: make FastSchematicWriterV3 work * fix/chore: write pos as doubles * chore: start on reader (class exists at least) * chore: replace while loop with simple if as char can be max 2 bytes * chore/feat: more work on the fast v3 reader * fix: offset must be inverted for origin * chore: use the actual FileChannel for mark / reset (if present) * chore: add null check again * chore: buffer streams in isFormat check * chore/feat: read schematic fully * chore: don't hold a lazyreference (seems harder to gc with already computed value?) * chore: remove debugs * chore: optimize FastSchematicReaderV3 * chore: remove logger warn for now * chore: constant not required anymore * chore/feat: support non-file based inputstreams (using in memory LZ4 cache) * chore: don't wrap streams unnecessary * chore: cleanup * chore: since comment for reader + writer * chore: FAST_V3 not for testing anymore * chore: update schematic and clipboard logic for linbus changes * chore: undo format check on load * fix: remove usages of old nbt types * fix: use LinBus in FaweDelegateSchematicHandler * fix: use ReaderUtil again * chore: update supported schematic types for Arkitektonika * chore: check for magic bytes in schematic (not tested yet) * revert: magic bytes check * fix: fix paletteAlreadyInitialized + biome placement on linear clipboards * Update worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriterV3.java --------- Co-authored-by: Octavia Togami Co-authored-by: Hannes Greule --- .../FaweDelegateSchematicHandler.java | 16 +- .../bukkit/util/DoNotMiniseThese.java | 4 + ...Reader.java => FastSchematicReaderV2.java} | 4 +- .../clipboard/io/FastSchematicReaderV3.java | 818 ++++++++++++++++++ ...Writer.java => FastSchematicWriterV2.java} | 8 +- .../clipboard/io/FastSchematicWriterV3.java | 295 +++++++ .../internal/io/VarIntStreamIterator.java | 70 ++ .../core/jnbt/CompressedSchematicTag.java | 4 +- .../java/com/sk89q/jnbt/NBTInputStream.java | 2 +- .../clipboard/io/BuiltInClipboardFormat.java | 280 ++++-- .../extent/clipboard/io/ClipboardFormat.java | 25 +- .../clipboard/io/NBTSchematicReader.java | 4 + .../extent/clipboard/io/SchematicNbtUtil.java | 61 ++ .../clipboard/io/SpongeSchematicReader.java | 453 ---------- .../BuiltInClipboardShareDestinations.java | 11 +- .../clipboard/io/sponge/ReaderUtil.java | 283 ++++++ .../io/sponge/SpongeSchematicV1Reader.java | 134 +++ .../io/sponge/SpongeSchematicV2Reader.java | 144 +++ .../SpongeSchematicV2Writer.java} | 188 ++-- .../io/sponge/SpongeSchematicV3Reader.java | 168 ++++ .../io/sponge/SpongeSchematicV3Writer.java | 233 +++++ .../io/sponge/VersionedDataFixer.java | 47 + .../clipboard/io/sponge/WriterUtil.java | 91 ++ .../clipboard/io/sponge/package-info.java | 26 + .../internal/util/VarIntIterator.java | 81 ++ 25 files changed, 2815 insertions(+), 635 deletions(-) rename worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/{FastSchematicReader.java => FastSchematicReaderV2.java} (99%) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java rename worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/{FastSchematicWriter.java => FastSchematicWriterV2.java} (98%) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriterV3.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/io/VarIntStreamIterator.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicNbtUtil.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/ReaderUtil.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV1Reader.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV2Reader.java rename worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/{SpongeSchematicWriter.java => sponge/SpongeSchematicV2Writer.java} (51%) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Reader.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Writer.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/VersionedDataFixer.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/WriterUtil.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/package-info.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/VarIntIterator.java diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java index 4b798981e..5c6f97d21 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java @@ -3,8 +3,8 @@ package com.fastasyncworldedit.bukkit.regions.plotsquared; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.FaweAPI; import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReader; -import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriter; +import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV2; +import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriterV2; import com.fastasyncworldedit.core.jnbt.CompressedCompoundTag; import com.fastasyncworldedit.core.jnbt.CompressedSchematicTag; import com.fastasyncworldedit.core.util.IOUtil; @@ -29,17 +29,19 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.MCEditSchematicReader; -import com.sk89q.worldedit.extent.clipboard.io.SpongeSchematicReader; +import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Reader; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import net.jpountz.lz4.LZ4BlockInputStream; import org.anarres.parallelgzip.ParallelGZIPOutputStream; import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.stream.LinBinaryIO; import javax.annotation.Nonnull; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; +import java.io.DataInputStream; import java.io.EOFException; import java.io.File; import java.io.FileNotFoundException; @@ -182,7 +184,7 @@ public class FaweDelegateSchematicHandler { try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream( new BufferedOutputStream(new ParallelGZIPOutputStream(stream)))) { - new FastSchematicWriter(output).write(clipboard); + new FastSchematicWriterV2(output).write(clipboard); } } else { try (OutputStream stream = new FileOutputStream(tmp); @@ -239,7 +241,7 @@ public class FaweDelegateSchematicHandler { public Schematic getSchematic(@Nonnull InputStream is) { try { - FastSchematicReader schematicReader = new FastSchematicReader( + FastSchematicReaderV2 schematicReader = new FastSchematicReaderV2( new NBTInputStream(new BufferedInputStream(new GZIPInputStream(new BufferedInputStream(is))))); Clipboard clip = schematicReader.read(); return new Schematic(clip); @@ -249,8 +251,8 @@ public class FaweDelegateSchematicHandler { return null; } try { - SpongeSchematicReader schematicReader = - new SpongeSchematicReader(new NBTInputStream(new GZIPInputStream(is))); + SpongeSchematicV3Reader schematicReader = + new SpongeSchematicV3Reader(LinBinaryIO.read(new DataInputStream(new GZIPInputStream(is)))); Clipboard clip = schematicReader.read(); return new Schematic(clip); } catch (IOException e2) { diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/DoNotMiniseThese.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/DoNotMiniseThese.java index 9916a7d9f..28fb6d990 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/DoNotMiniseThese.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/DoNotMiniseThese.java @@ -1,6 +1,8 @@ package com.fastasyncworldedit.bukkit.util; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.io.FastBufferedInputStream; +import it.unimi.dsi.fastutil.io.FastBufferedOutputStream; import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.longs.LongArraySet; import it.unimi.dsi.fastutil.longs.LongIterator; @@ -19,5 +21,7 @@ final class DoNotMiniseThese { private final LongSet d = null; private final Int2ObjectMap e = null; private final Object2ObjectArrayMap f = null; + private final FastBufferedInputStream g = null; + private final FastBufferedOutputStream h = null; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV2.java similarity index 99% rename from worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java rename to worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV2.java index 71d139789..97fdd1f27 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV2.java @@ -53,7 +53,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Reads schematic files using the Sponge Schematic Specification. */ -public class FastSchematicReader extends NBTSchematicReader { +public class FastSchematicReaderV2 extends NBTSchematicReader { private static final Logger LOGGER = LogManagerCompat.getLogger(); private final NBTInputStream inputStream; @@ -88,7 +88,7 @@ public class FastSchematicReader extends NBTSchematicReader { * * @param inputStream the input stream to read from */ - public FastSchematicReader(NBTInputStream inputStream) { + public FastSchematicReaderV2(NBTInputStream inputStream) { checkNotNull(inputStream); this.inputStream = inputStream; this.fixer = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataFixer(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java new file mode 100644 index 000000000..db98d2203 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java @@ -0,0 +1,818 @@ +package com.fastasyncworldedit.core.extent.clipboard.io; + +import com.fastasyncworldedit.core.extent.clipboard.LinearClipboard; +import com.fastasyncworldedit.core.extent.clipboard.SimpleClipboard; +import com.fastasyncworldedit.core.internal.io.ResettableFileInputStream; +import com.fastasyncworldedit.core.internal.io.VarIntStreamIterator; +import com.fastasyncworldedit.core.math.MutableBlockVector3; +import com.fastasyncworldedit.core.util.IOUtil; +import com.fastasyncworldedit.core.util.MathMan; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.NBTConstants; +import com.sk89q.jnbt.NBTInputStream; +import com.sk89q.jnbt.NBTOutputStream; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; +import com.sk89q.worldedit.extent.clipboard.io.sponge.ReaderUtil; +import com.sk89q.worldedit.extent.clipboard.io.sponge.VersionedDataFixer; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import com.sk89q.worldedit.world.entity.EntityType; +import it.unimi.dsi.fastutil.io.FastBufferedInputStream; +import it.unimi.dsi.fastutil.io.FastBufferedOutputStream; +import net.jpountz.lz4.LZ4BlockInputStream; +import net.jpountz.lz4.LZ4BlockOutputStream; +import org.apache.logging.log4j.Logger; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.jetbrains.annotations.ApiStatus; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.OptionalInt; +import java.util.Set; +import java.util.UUID; +import java.util.function.BooleanSupplier; +import java.util.function.Function; +import java.util.zip.GZIPInputStream; + +/** + * ClipboardReader for the Sponge Schematic Format v3. + * Not necessarily much faster than {@link com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Reader}, but uses a + * stream based approach to keep the memory overhead minimal (especially in larger schematics) + * + * @since TODO + */ +@SuppressWarnings("removal") // JNBT +public class FastSchematicReaderV3 implements ClipboardReader { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static final byte CACHE_IDENTIFIER_END = 0x00; + private static final byte CACHE_IDENTIFIER_BLOCK = 0x01; + private static final byte CACHE_IDENTIFIER_BIOMES = 0x02; + private static final byte CACHE_IDENTIFIER_ENTITIES = 0x03; + private static final byte CACHE_IDENTIFIER_BLOCK_TILE_ENTITIES = 0x04; + + private final InputStream parentStream; + private final MutableBlockVector3 dimensions = MutableBlockVector3.at(0, 0, 0); + private final Set remainingTags; + + private DataInputStream dataInputStream; + private NBTInputStream nbtInputStream; + + private VersionedDataFixer dataFixer; + private BlockVector3 offset; + private BlockState[] blockPalette; + private BiomeType[] biomePalette; + private int dataVersion = -1; + + // Only used if the InputStream is not file based (and therefor does not support resets based on FileChannels) + // and the file is unordered + // Data and Palette cache is separated, as the data requires a fully populated palette - and the order is not guaranteed + private byte[] dataCache; + private byte[] paletteCache; + private OutputStream dataCacheWriter; + private OutputStream paletteCacheWriter; + + + public FastSchematicReaderV3(@NonNull InputStream stream) { + Objects.requireNonNull(stream, "stream"); + if (stream instanceof ResettableFileInputStream) { + stream.mark(Integer.MAX_VALUE); + this.remainingTags = new HashSet<>(); + } else if (stream instanceof FileInputStream fileInputStream) { + stream = new ResettableFileInputStream(fileInputStream); + stream.mark(Integer.MAX_VALUE); + this.remainingTags = new HashSet<>(); + } else if (stream instanceof FastBufferedInputStream || stream instanceof BufferedInputStream) { + this.remainingTags = null; + } else { + stream = new FastBufferedInputStream(stream); + this.remainingTags = null; + } + this.parentStream = stream; + } + + @Override + public Clipboard read(final UUID uuid, final Function createOutput) throws IOException { + Clipboard clipboard = null; + + this.setSubStreams(); + skipHeader(this.dataInputStream); + + byte type; + String tag; + while ((type = dataInputStream.readByte()) != NBTConstants.TYPE_END) { + tag = this.dataInputStream.readUTF(); + switch (tag) { + case "DataVersion" -> { + final Platform platform = + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING); + this.dataVersion = this.dataInputStream.readInt(); + this.dataFixer = ReaderUtil.getVersionedDataFixer(this.dataVersion, platform, platform.getDataVersion()); + } + case "Offset" -> { + this.dataInputStream.skipNBytes(4); // Array Length field (4 byte int) + this.offset = BlockVector3.at( + this.dataInputStream.readInt(), + this.dataInputStream.readInt(), + this.dataInputStream.readInt() + ); + } + case "Width" -> this.dimensions.mutX(this.dataInputStream.readShort() & 0xFFFF); + case "Height" -> this.dimensions.mutY(this.dataInputStream.readShort() & 0xFFFF); + case "Length" -> this.dimensions.mutZ(this.dataInputStream.readShort() & 0xFFFF); + case "Blocks" -> readBlocks(clipboard); + case "Biomes" -> readBiomes(clipboard); + case "Entities" -> readEntities(clipboard); + default -> this.nbtInputStream.readTagPayloadLazy(type, 0); + } + if (clipboard == null && this.areDimensionsAvailable()) { + clipboard = createOutput.apply(this.dimensions); + } + } + + if (clipboard == null) { + throw new IOException("Invalid schematic - missing dimensions"); + } + if (dataFixer == null) { + throw new IOException("Invalid schematic - missing DataVersion"); + } + + if (this.supportsReset() && !remainingTags.isEmpty()) { + readRemainingDataReset(clipboard); + } else if (this.dataCacheWriter != null || this.paletteCacheWriter != null) { + readRemainingDataCache(clipboard); + } + + clipboard.setOrigin(this.offset.multiply(-1)); + if (clipboard instanceof SimpleClipboard simpleClipboard && !this.offset.equals(BlockVector3.ZERO)) { + clipboard = new BlockArrayClipboard(simpleClipboard, this.offset); + } + return clipboard; + } + + + /** + * Reads all locally cached data (due to reset not being available) and applies them to the clipboard. + *

    + * Firstly, closes all cache writers (which adds the END identifier to each and fills the cache byte arrays on this instance) + * If required, creates all missing palettes first (as needed by all remaining data). + * At last writes all missing data (block states, tile entities, biomes, entities). + * + * @param clipboard The clipboard to write into. + * @throws IOException on I/O error. + */ + private void readRemainingDataCache(Clipboard clipboard) throws IOException { + byte identifier; + if (this.paletteCacheWriter != null) { + this.paletteCacheWriter.close(); + } + if (this.dataCacheWriter != null) { + this.dataCacheWriter.close(); + } + if (this.paletteCache != null) { + try (final DataInputStream cacheStream = new DataInputStream(new FastBufferedInputStream( + new LZ4BlockInputStream(new FastBufferedInputStream(new ByteArrayInputStream(this.paletteCache)))))) { + while ((identifier = cacheStream.readByte()) != CACHE_IDENTIFIER_END) { + if (identifier == CACHE_IDENTIFIER_BLOCK) { + this.readPaletteMap(cacheStream, this.provideBlockPaletteInitializer()); + continue; + } + if (identifier == CACHE_IDENTIFIER_BIOMES) { + this.readPaletteMap(cacheStream, this.provideBiomePaletteInitializer()); + continue; + } + throw new IOException("invalid cache state - got identifier: 0x" + identifier); + } + } + } + try (final DataInputStream cacheStream = new DataInputStream(new FastBufferedInputStream( + new LZ4BlockInputStream(new FastBufferedInputStream(new ByteArrayInputStream(this.dataCache))))); + final NBTInputStream cacheNbtIn = new NBTInputStream(cacheStream)) { + while ((identifier = cacheStream.readByte()) != CACHE_IDENTIFIER_END) { + switch (identifier) { + case CACHE_IDENTIFIER_BLOCK -> this.readPaletteData(cacheStream, this.getBlockWriter(clipboard)); + case CACHE_IDENTIFIER_BIOMES -> this.readPaletteData(cacheStream, this.getBiomeWriter(clipboard)); + case CACHE_IDENTIFIER_ENTITIES -> { + cacheStream.skipNBytes(1); // list child type (TAG_Compound) + this.readEntityContainers( + cacheStream, + cacheNbtIn, + DataFixer.FixTypes.ENTITY, + this.provideEntityTransformer(clipboard) + ); + } + case CACHE_IDENTIFIER_BLOCK_TILE_ENTITIES -> { + cacheStream.skipNBytes(1); // list child type (TAG_Compound) + this.readEntityContainers( + cacheStream, + cacheNbtIn, + DataFixer.FixTypes.BLOCK_ENTITY, + this.provideTileEntityTransformer(clipboard) + ); + } + default -> throw new IOException("invalid cache state - got identifier: 0x" + identifier); + } + } + } + } + + /** + * Reset the main stream of this clipboard and reads all remaining data that could not be read or fixed yet. + * Might need two iterations if the DataVersion tag is after the Blocks tag while the Palette inside the Blocks tag is not + * at the first position. + * + * @param clipboard The clipboard to write into. + * @throws IOException on I/O error. + */ + private void readRemainingDataReset(Clipboard clipboard) throws IOException { + byte type; + String tag; + outer: + while (!this.remainingTags.isEmpty()) { + this.reset(); + skipHeader(this.dataInputStream); + while ((type = dataInputStream.readByte()) != NBTConstants.TYPE_END) { + tag = dataInputStream.readUTF(); + byte b = tag.equals("Blocks") ? CACHE_IDENTIFIER_BLOCK : + tag.equals("Biomes") ? CACHE_IDENTIFIER_BIOMES : + tag.equals("Entities") ? CACHE_IDENTIFIER_ENTITIES : + CACHE_IDENTIFIER_END; + if (!this.remainingTags.remove(b)) { + this.nbtInputStream.readTagPayloadLazy(type, 0); + continue; + } + switch (tag) { + case "Blocks" -> readBlocks(clipboard); + case "Biomes" -> readBiomes(clipboard); + case "Entities" -> readEntities(clipboard); + default -> this.nbtInputStream.readTagPayloadLazy(type, 0); // Should never happen, but just in case + } + if (this.remainingTags.isEmpty()) { + break outer; + } + } + } + } + + /** + * {@inheritDoc} + *

    + * Requires {@link #read()}, {@link #read(UUID)} or {@link #read(UUID, Function)} to be called before. + */ + @Override + public OptionalInt getDataVersion() { + return this.dataVersion > -1 ? OptionalInt.of(this.dataVersion) : OptionalInt.empty(); + } + + private void readBlocks(Clipboard target) throws IOException { + this.blockPalette = new BlockState[BlockTypesCache.states.length]; + readPalette( + target != null, + CACHE_IDENTIFIER_BLOCK, + () -> this.blockPalette[0] != null, + this.provideBlockPaletteInitializer(), + this.getBlockWriter(target), + (type, tag) -> { + if (!tag.equals("BlockEntities")) { + try { + this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_LIST, 0); + } catch (IOException e) { + LOGGER.error("Failed to skip additional tag", e); + } + return; + } + try { + this.readTileEntities(target); + } catch (IOException e) { + LOGGER.warn("Failed to read tile entities", e); + } + } + ); + } + + private void readBiomes(Clipboard target) throws IOException { + this.biomePalette = new BiomeType[BiomeType.REGISTRY.size()]; + readPalette( + target != null, + CACHE_IDENTIFIER_BIOMES, + () -> this.biomePalette[0] != null, + this.provideBiomePaletteInitializer(), + this.getBiomeWriter(target), + (type, tag) -> { + try { + this.nbtInputStream.readTagPayloadLazy(type, 0); + } catch (IOException e) { + LOGGER.error("Failed to skip additional tag in biome container: {}", tag, e); + } + } + ); + } + + private void readEntities(@Nullable Clipboard target) throws IOException { + if (target == null || this.dataFixer == null) { + if (supportsReset()) { + this.remainingTags.add(CACHE_IDENTIFIER_ENTITIES); + this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_LIST, 0); + return; + } + // Easier than streaming for now + final NBTOutputStream cacheStream = new NBTOutputStream(this.getDataCacheWriter()); + cacheStream.writeByte(CACHE_IDENTIFIER_ENTITIES); + cacheStream.writeTagPayload(this.nbtInputStream.readTagPayload(NBTConstants.TYPE_LIST, 0)); + return; + } + if (this.dataInputStream.read() != NBTConstants.TYPE_COMPOUND) { + throw new IOException("Expected a compound block for entity"); + } + this.readEntityContainers( + this.dataInputStream, this.nbtInputStream, DataFixer.FixTypes.ENTITY, this.provideEntityTransformer(target) + ); + } + + private void readTileEntities(Clipboard target) throws IOException { + if (target == null || this.dataFixer == null) { + if (supportsReset()) { + this.remainingTags.add(CACHE_IDENTIFIER_BLOCK); // use block identifier, as this method will be called by + // readBlocks again + this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_LIST, 0); + return; + } + // Easier than streaming for now + final NBTOutputStream cacheStream = new NBTOutputStream(this.getDataCacheWriter()); + cacheStream.writeByte(CACHE_IDENTIFIER_BLOCK_TILE_ENTITIES); + cacheStream.writeTagPayload(this.nbtInputStream.readTagPayload(NBTConstants.TYPE_LIST, 0)); + return; + } + if (this.dataInputStream.read() != NBTConstants.TYPE_COMPOUND) { + throw new IOException("Expected a compound block for tile entity"); + } + this.readEntityContainers( + this.dataInputStream, + this.nbtInputStream, + DataFixer.FixTypes.BLOCK_ENTITY, + this.provideTileEntityTransformer(target) + ); + } + + private void readEntityContainers( + DataInputStream stream, + NBTInputStream nbtStream, + DataFixer.FixType fixType, + EntityTransformer transformer + ) throws IOException { + double x, y, z; + LinCompoundTag tag; + String id; + byte type; + int count = stream.readInt(); + while (count-- > 0) { + x = -1; + y = -1; + z = -1; + tag = null; + id = null; + while ((type = stream.readByte()) != NBTConstants.TYPE_END) { + switch (type) { + // Depending on the type of entity container (tile vs "normal") the pos consists of either doubles or ints + case NBTConstants.TYPE_INT_ARRAY -> { + if (!stream.readUTF().equals("Pos")) { + throw new IOException("Expected INT_ARRAY tag to be Pos"); + } + stream.skipNBytes(4); // count of following ints - for pos = 3 + x = stream.readInt(); + y = stream.readInt(); + z = stream.readInt(); + } + case NBTConstants.TYPE_LIST -> { + if (!stream.readUTF().equals("Pos")) { + throw new IOException("Expected LIST tag to be Pos"); + } + if (stream.readByte() != NBTConstants.TYPE_DOUBLE) { + throw new IOException("Expected LIST Pos tag to contain DOUBLE"); + } + stream.skipNBytes(4); // count of following doubles - for pos = 3 + x = stream.readDouble(); + y = stream.readDouble(); + z = stream.readDouble(); + } + case NBTConstants.TYPE_STRING -> { + if (!stream.readUTF().equals("Id")) { + throw new IOException("Expected STRING tag to be Id"); + } + id = stream.readUTF(); + } + case NBTConstants.TYPE_COMPOUND -> { + if (!stream.readUTF().equals("Data")) { + throw new IOException("Expected COMPOUND tag to be Data"); + } + if (!(nbtStream.readTagPayload(NBTConstants.TYPE_COMPOUND, 0).toLinTag() instanceof LinCompoundTag lin)) { + throw new IOException("Data tag could not be read into LinCompoundTag"); + } + tag = lin; + } + default -> throw new IOException("Unexpected tag in compound: " + type); + } + } + if (id == null) { + throw new IOException("Missing Id tag in compound"); + } + if (x < 0 || y < 0 || z < 0) { + throw new IOException("Missing position for entity " + id); + } + if (tag == null) { + transformer.transform(x, y, z, id, LinCompoundTag.of(Map.of())); + continue; + } + tag = this.dataFixer.fixUp(fixType, tag); + if (tag == null) { + LOGGER.warn("Failed to fix-up entity for {} @ {},{},{} - skipping", id, x, y, z); + continue; + } + transformer.transform(x, y, z, id, tag); + } + } + + /** + * The `Palette` tag is required first, as that contains the information of the actual palette size. + * Keeping the whole Data block in memory - which *could* be compressed - is just not it + * + * @param paletteInitializer Invoked for each 'Palette' entry using the actual palette value (e.g. block state) + index + * @param paletteDataApplier Invoked for each 'Data' entry using the data index and the palette index at the data index + */ + private void readPalette( + boolean hasClipboard, + byte paletteType, + BooleanSupplier paletteAlreadyInitialized, + PaletteInitializer paletteInitializer, + PaletteDataApplier paletteDataApplier, + AdditionalTagConsumer additionalTag + ) throws IOException { + boolean hasPalette = paletteAlreadyInitialized.getAsBoolean(); + byte type; + String tag; + while ((type = this.dataInputStream.readByte()) != NBTConstants.TYPE_END) { + tag = this.dataInputStream.readUTF(); + if (tag.equals("Palette")) { + if (hasPalette) { + // Skip palette, as already exists + this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_COMPOUND, 0); + continue; + } + if (!this.readPaletteMap(this.dataInputStream, paletteInitializer)) { + if (this.supportsReset()) { + // Couldn't read - skip palette for now + this.remainingTags.add(paletteType); + this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_COMPOUND, 0); + continue; + } + // Reset not possible, write into cache + final NBTOutputStream cacheWriter = new NBTOutputStream(this.getPaletteCacheWriter()); + cacheWriter.write(paletteType); + cacheWriter.writeTagPayload(this.nbtInputStream.readTagPayload(NBTConstants.TYPE_COMPOUND, 0)); + continue; + } + hasPalette = true; + continue; + } + if (tag.equals("Data")) { + // No palette or dimensions are yet available + if (!hasPalette || this.dataFixer == null || !hasClipboard) { + if (this.supportsReset()) { + this.remainingTags.add(paletteType); + this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_BYTE_ARRAY, 0); + continue; + } + // Reset not possible, write into cache + int byteLen = this.dataInputStream.readInt(); + final DataOutputStream cacheWriter = new DataOutputStream(this.getDataCacheWriter()); + cacheWriter.write(paletteType); + cacheWriter.writeInt(byteLen); + IOUtil.copy(this.dataInputStream, cacheWriter, byteLen); + continue; + } + this.readPaletteData(this.dataInputStream, paletteDataApplier); + continue; + } + additionalTag.accept(type, tag); + } + } + + private void readPaletteData(DataInputStream stream, PaletteDataApplier applier) throws IOException { + int length = stream.readInt(); + // Write data into clipboard + int i = 0; + if (needsVarIntReading(length)) { + for (var iter = new VarIntStreamIterator(stream, length); iter.hasNext(); i++) { + applier.apply(i, (char) iter.nextInt()); + } + return; + } + while (i < length) { + applier.apply(i++, (char) stream.readUnsignedByte()); + } + } + + /** + * Reads the CompoundTag containing the palette mapping ({@code index: value}) and passes each entry to the + * {@link PaletteInitializer}. + *

    + * This method expects that the identifier ({@link NBTConstants#TYPE_COMPOUND}) is already consumed from the stream. + * + * @param stream The stream to read the data from. + * @param initializer The initializer called for each entry with its index and backed value. + * @return {@code true} if the mapping could be read, {@code false} otherwise (e.g. DataFixer is not yet available). + * @throws IOException on I/O error. + */ + private boolean readPaletteMap(DataInputStream stream, PaletteInitializer initializer) throws IOException { + if (this.dataFixer == null) { + return false; + } + while (stream.readByte() != NBTConstants.TYPE_END) { + String value = stream.readUTF(); + char index = (char) stream.readInt(); + initializer.initialize(index, value); + } + return true; + } + + private void indexToPosition(int index, PositionConsumer supplier) { + int y = index / (dimensions.x() * dimensions.z()); + int remainder = index - (y * dimensions.x() * dimensions.z()); + int z = remainder / dimensions.x(); + int x = remainder - z * dimensions.x(); + supplier.accept(x, y, z); + } + + private PaletteDataApplier getBlockWriter(Clipboard target) { + if (target instanceof LinearClipboard linearClipboard) { + return (index, ordinal) -> linearClipboard.setBlock(index, this.blockPalette[ordinal]); + } + return (index, ordinal) -> indexToPosition(index, (x, y, z) -> target.setBlock(x, y, z, this.blockPalette[ordinal])); + } + + private PaletteDataApplier getBiomeWriter(Clipboard target) { + return (index, ordinal) -> indexToPosition(index, (x, y, z) -> target.setBiome(x, y, z, this.biomePalette[ordinal])); + } + + private PaletteInitializer provideBlockPaletteInitializer() { + return (index, value) -> { + if (this.dataFixer == null) { + throw new IllegalStateException("Can't read block palette map if DataFixer is not yet available"); + } + value = dataFixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, value); + try { + this.blockPalette[index] = BlockState.get(value); + } catch (InputParseException e) { + LOGGER.warn("Invalid BlockState in palette: {}. Block will be replaced with air.", value); + this.blockPalette[index] = BlockTypes.AIR.getDefaultState(); + } + }; + } + + private PaletteInitializer provideBiomePaletteInitializer() { + return (index, value) -> { + if (this.dataFixer == null) { + throw new IllegalStateException("Can't read biome palette map if DataFixer is not yet available"); + } + value = dataFixer.fixUp(DataFixer.FixTypes.BIOME, value); + BiomeType biomeType = BiomeTypes.get(value); + if (biomeType == null) { + biomeType = BiomeTypes.PLAINS; + LOGGER.warn("Invalid biome type in palette: {}. Biome will be replaced with plains.", value); + } + this.biomePalette[index] = biomeType; + }; + } + + private EntityTransformer provideEntityTransformer(Clipboard clipboard) { + return (x, y, z, id, tag) -> { + EntityType type = EntityType.REGISTRY.get(id); + if (type == null) { + LOGGER.warn("Invalid entity id: {} - skipping", id); + return; + } + clipboard.createEntity( + new Location(clipboard, Location.at(x, y, z).add(clipboard.getMinimumPoint().toVector3())), + new BaseEntity(type, LazyReference.computed(tag)) + ); + }; + } + + private EntityTransformer provideTileEntityTransformer(Clipboard clipboard) { + //noinspection deprecation + return (x, y, z, id, tag) -> clipboard.setTile( + MathMan.roundInt(x + clipboard.getMinimumPoint().x()), + MathMan.roundInt(y + clipboard.getMinimumPoint().y()), + MathMan.roundInt(z + clipboard.getMinimumPoint().z()), + new CompoundTag(tag) + ); + } + + /** + * @return {@code true} if {@code Width}, {@code Length} and {@code Height} are already read from the stream + */ + private boolean areDimensionsAvailable() { + return this.dimensions.x() != 0 && this.dimensions.y() != 0 && this.dimensions.z() != 0; + } + + /** + * Closes this reader instance and all underlying resources. + * + * @throws IOException on I/O error. + */ + @Override + public void close() throws IOException { + parentStream.close(); // closes all underlying resources implicitly + } + + /** + * Resets the main stream to the previously marked position ({@code 0}), if supported (see {@link #supportsReset()}). + * If the stream is reset, the sub streams (for DataInput and NBT) are re-created to respect the new position. + * + * @throws IOException on I/O error. + */ + private void reset() throws IOException { + if (this.supportsReset()) { + this.parentStream.reset(); + this.parentStream.mark(Integer.MAX_VALUE); + this.setSubStreams(); + } + } + + /** + * @return {@code true} if the stream used while instantiating the reader supports resets (without memory overhead). + */ + private boolean supportsReset() { + return this.remainingTags != null; + } + + /** + * Overwrites the DataInput- and NBT-InputStreams (e.g. when the marker of the backed stream updated). + * + * @throws IOException on I/O error. + */ + private void setSubStreams() throws IOException { + final FastBufferedInputStream buffer = new FastBufferedInputStream(new GZIPInputStream(this.parentStream)); + this.dataInputStream = new DataInputStream(buffer); + this.nbtInputStream = new NBTInputStream(buffer); + } + + /** + * Creates a new cache writer for non-palette data, if none exists yet. + * Returns either the already created or new one. + * + * @return the output stream for non-palette cache data. + */ + private OutputStream getDataCacheWriter() { + if (this.dataCacheWriter == null) { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(512); + this.dataCacheWriter = new FastBufferedOutputStream(new LZ4BlockOutputStream(byteArrayOutputStream)) { + @Override + public void close() throws IOException { + this.write(CACHE_IDENTIFIER_END); + super.close(); + FastSchematicReaderV3.this.dataCache = byteArrayOutputStream.toByteArray(); + } + }; + } + return this.dataCacheWriter; + } + + /** + * Creates a new cache writer for palette data, if none exists yet. + * Returns either the already created or new one. + * + * @return the output stream for palette cache data. + */ + private OutputStream getPaletteCacheWriter() { + if (this.paletteCacheWriter == null) { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(256); + this.paletteCacheWriter = new FastBufferedOutputStream(new LZ4BlockOutputStream(byteArrayOutputStream)) { + @Override + public void close() throws IOException { + this.write(CACHE_IDENTIFIER_END); + super.close(); + FastSchematicReaderV3.this.paletteCache = byteArrayOutputStream.toByteArray(); + } + }; + } + return this.paletteCacheWriter; + } + + private boolean needsVarIntReading(int byteArrayLength) { + return byteArrayLength > this.dimensions.x() * this.dimensions.y() * this.dimensions.z(); + } + + /** + * Skips the schematic header including the root compound (empty name) and the root's child compound ("Schematic") + * + * @param dataInputStream The stream containing the schematic data to skip + * @throws IOException on I/O error + */ + private static void skipHeader(DataInputStream dataInputStream) throws IOException { + dataInputStream.skipNBytes(1 + 2); // 1 Byte = TAG_Compound, 2 Bytes = Short (Length of tag name = "") + dataInputStream.skipNBytes(1 + 2 + 9); // as above + 9 bytes = "Schematic" + } + + @ApiStatus.Internal + @FunctionalInterface + private interface PositionConsumer { + + /** + * Called with block location coordinates. + * + * @param x the x coordinate. + * @param y the y coordinate. + * @param z the z coordinate. + */ + void accept(int x, int y, int z); + + } + + @ApiStatus.Internal + @FunctionalInterface + private interface EntityTransformer { + + /** + * Called for each entity from the Schematics {@code Entities} compound list. + * + * @param x the relative x coordinate of the entity. + * @param y the relative y coordinate of the entity. + * @param z the relative z coordinate of the entity. + * @param id the entity id as a resource location (e.g. {@code minecraft:sheep}). + * @param tag the - already fixed, if required - nbt data of the entity. + */ + void transform(double x, double y, double z, String id, LinCompoundTag tag); + + } + + @ApiStatus.Internal + @FunctionalInterface + private interface PaletteInitializer { + + /** + * Called for each palette entry (the mapping part, not data). + * + * @param index the index of the entry, as used in the Data byte array. + * @param value the value for this entry (either biome type as resource location or the block state as a string). + */ + void initialize(char index, String value); + + } + + @ApiStatus.Internal + @FunctionalInterface + private interface PaletteDataApplier { + + /** + * Called for each palette data entry (not the mapping part, but the var-int byte array). + * + * @param index The index of this data entry (due to var-int behaviour not necessarily the index in the data byte array). + * @param ordinal The ordinal of this entry as defined in the palette mapping. + */ + void apply(int index, char ordinal); + + } + + @ApiStatus.Internal + @FunctionalInterface + private interface AdditionalTagConsumer { + + /** + * Called for each unknown nbt tag. + * + * @param type The type of the tag (as defined by the constants in {@link NBTConstants}). + * @param name The name of the tag. + */ + void accept(byte type, String name); + + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriterV2.java similarity index 98% rename from worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java rename to worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriterV2.java index ac86fb249..3bd302876 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriterV2.java @@ -48,9 +48,9 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Writes schematic files using the Sponge schematic format. */ -public class FastSchematicWriter implements ClipboardWriter { +public class FastSchematicWriterV2 implements ClipboardWriter { - private static final int CURRENT_VERSION = 2; + public static final int CURRENT_VERSION = 2; private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE; private final NBTOutputStream outputStream; @@ -61,7 +61,7 @@ public class FastSchematicWriter implements ClipboardWriter { * * @param outputStream the output stream to write to */ - public FastSchematicWriter(NBTOutputStream outputStream) { + public FastSchematicWriterV2(NBTOutputStream outputStream) { checkNotNull(outputStream); this.outputStream = outputStream; } @@ -103,11 +103,11 @@ public class FastSchematicWriter implements ClipboardWriter { final DataOutput rawStream = outputStream.getOutputStream(); outputStream.writeLazyCompoundTag("Schematic", out -> { + out.writeNamedTag("Version", CURRENT_VERSION); out.writeNamedTag( "DataVersion", WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion() ); - out.writeNamedTag("Version", CURRENT_VERSION); out.writeNamedTag("Width", (short) width); out.writeNamedTag("Height", (short) height); out.writeNamedTag("Length", (short) length); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriterV3.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriterV3.java new file mode 100644 index 000000000..e00839eb0 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriterV3.java @@ -0,0 +1,295 @@ +package com.fastasyncworldedit.core.extent.clipboard.io; + +import com.fastasyncworldedit.core.function.visitor.Order; +import com.fastasyncworldedit.core.util.IOUtil; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.NBTConstants; +import com.sk89q.jnbt.NBTOutputStream; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import net.jpountz.lz4.LZ4BlockInputStream; +import net.jpountz.lz4.LZ4BlockOutputStream; +import org.enginehub.linbus.tree.LinCompoundTag; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataOutput; +import java.io.IOException; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; + +/** + * Faster, stream-based implementation of {@link com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Writer} for + * writing schematics conforming the sponge schematic v3 format. + * + * @since TODO + */ +@SuppressWarnings("removal") // Yes, JNBT is deprecated - we know +public class FastSchematicWriterV3 implements ClipboardWriter { + + public static final int CURRENT_VERSION = 3; + + private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE; + private final NBTOutputStream outputStream; + + + public FastSchematicWriterV3(final NBTOutputStream outputStream) { + this.outputStream = Objects.requireNonNull(outputStream, "outputStream"); + } + + @Override + public void write(final Clipboard clipboard) throws IOException { + clipboard.flush(); + + // Validate dimensions before starting to write into stream + final Region region = clipboard.getRegion(); + if (region.getWidth() > MAX_SIZE) { + throw new IllegalArgumentException("Region width too large for schematic: " + region.getWidth()); + } + if (region.getHeight() > MAX_SIZE) { + throw new IllegalArgumentException("Region height too large for schematic: " + region.getHeight()); + } + if (region.getLength() > MAX_SIZE) { + throw new IllegalArgumentException("Region length too large for schematic: " + region.getLength()); + } + + this.outputStream.writeLazyCompoundTag( + "", root -> root.writeLazyCompoundTag("Schematic", out -> this.write2(out, clipboard)) + ); + } + + private void write2(NBTOutputStream schematic, Clipboard clipboard) throws IOException { + final Region region = clipboard.getRegion(); + final BlockVector3 origin = clipboard.getOrigin(); + final BlockVector3 min = clipboard.getMinimumPoint(); + final BlockVector3 offset = min.subtract(origin); + + schematic.writeNamedTag("Version", CURRENT_VERSION); + schematic.writeNamedTag( + "DataVersion", + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion() + ); + schematic.writeLazyCompoundTag("Metadata", out -> this.writeMetadata(out, clipboard)); + + schematic.writeNamedTag("Width", (short) region.getWidth()); + schematic.writeNamedTag("Height", (short) region.getHeight()); + schematic.writeNamedTag("Length", (short) region.getLength()); + + schematic.writeNamedTag("Offset", new int[]{ + offset.x(), offset.y(), offset.z() + }); + + schematic.writeLazyCompoundTag("Blocks", out -> this.writeBlocks(out, clipboard)); + if (clipboard.hasBiomes()) { + schematic.writeLazyCompoundTag("Biomes", out -> this.writeBiomes(out, clipboard)); + } + // Some clipboards have quite heavy operations on the getEntities method - only call once + List entities; + if (!(entities = clipboard.getEntities()).isEmpty()) { + schematic.writeNamedTagName("Entities", NBTConstants.TYPE_LIST); + schematic.write(NBTConstants.TYPE_COMPOUND); + schematic.writeInt(entities.size()); + for (final Entity entity : entities) { + this.writeEntity(schematic, clipboard, entity); + } + } + } + + private void writeBlocks(NBTOutputStream blocks, Clipboard clipboard) throws IOException { + final int[] tiles = new int[]{0}; + final ByteArrayOutputStream tileBytes = new ByteArrayOutputStream(); + try (LZ4BlockOutputStream lz4Stream = new LZ4BlockOutputStream(tileBytes); + NBTOutputStream tileOut = new NBTOutputStream(lz4Stream)) { + this.writePalette( + blocks, + BlockTypesCache.states.length, + pos -> { + BaseBlock block = pos.getFullBlock(clipboard); + LinCompoundTag tag; + if ((tag = block.getNbt()) != null) { + tiles[0]++; + try { + tileOut.writeNamedTag("Id", block.getNbtId()); + tileOut.writeNamedTag("Pos", new int[]{ + pos.x() - clipboard.getMinimumPoint().x(), + pos.y() - clipboard.getMinimumPoint().y(), + pos.z() - clipboard.getMinimumPoint().z() + }); + //noinspection deprecation + tileOut.writeNamedTag("Data", new CompoundTag(tag)); + tileOut.write(NBTConstants.TYPE_END); + } catch (IOException e) { + throw new RuntimeException("Failed to write tile data", e); + } + } + return block; + }, + block -> { + char ordinal = block.getOrdinalChar(); + if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { + ordinal = BlockTypesCache.ReservedIDs.AIR; + } + return ordinal; + }, + BlockStateHolder::getAsString, + clipboard + ); + lz4Stream.finish(); + } finally { + // Write Tiles + if (tiles[0] > 0) { + blocks.writeNamedTagName("BlockEntities", NBTConstants.TYPE_LIST); + blocks.write(NBTConstants.TYPE_COMPOUND); + blocks.writeInt(tiles[0]); + // Decompress cached data again + try (LZ4BlockInputStream reader = new LZ4BlockInputStream(new ByteArrayInputStream(tileBytes.toByteArray()))) { + IOUtil.copy(reader, blocks.getOutputStream()); + } + } + } + } + + private void writeBiomes(NBTOutputStream biomes, Clipboard clipboard) throws IOException { + this.writePalette( + biomes, BiomeType.REGISTRY.size(), + pos -> pos.getBiome(clipboard), + biome -> (char) biome.getInternalId(), + BiomeType::id, + clipboard + ); + } + + private void writeEntity(NBTOutputStream out, Clipboard clipboard, Entity entity) throws IOException { + final BaseEntity state = entity.getState(); + if (state == null) { + throw new IOException("Entity has no state"); + } + out.writeNamedTag("Id", state.getType().id()); + + out.writeNamedTagName("Pos", NBTConstants.TYPE_LIST); + out.write(NBTConstants.TYPE_DOUBLE); + out.writeInt(3); + out.writeDouble(entity.getLocation().x() - clipboard.getMinimumPoint().x()); + out.writeDouble(entity.getLocation().y() - clipboard.getMinimumPoint().y()); + out.writeDouble(entity.getLocation().z() - clipboard.getMinimumPoint().z()); + + out.writeLazyCompoundTag("Data", data -> { + //noinspection deprecation + CompoundTag nbt = state.getNbtData(); + if (nbt != null) { + nbt.getValue().forEach((s, tag) -> { + if (s.equals("id") || s.equals("Rotation")) { + return; + } + try { + data.writeNamedTag(s, tag); + } catch (IOException e) { + throw new RuntimeException("failed to write entity data", e); + } + }); + } + + // Write rotation list + data.writeNamedTagName("Rotation", NBTConstants.TYPE_LIST); + data.write(NBTConstants.TYPE_FLOAT); + data.writeInt(2); + data.writeFloat(entity.getLocation().getYaw()); + data.writeFloat(entity.getLocation().getPitch()); + }); + + out.write(NBTConstants.TYPE_END); // End the compound + } + + private void writePalette( + NBTOutputStream out, int capacity, + Function objectResolver, + Function ordinalResolver, + Function paletteEntryResolver, + Clipboard clipboard + ) throws IOException { + int dataBytesUsed = 0; + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + try (LZ4BlockOutputStream dataOut = new LZ4BlockOutputStream(bytes)) { + int index = 0; + char[] palette = new char[capacity]; + Arrays.fill(palette, Character.MAX_VALUE); + final Iterator iterator = clipboard.iterator(Order.YZX); + // Start Palette tag + out.writeNamedTagName("Palette", NBTConstants.TYPE_COMPOUND); + while (iterator.hasNext()) { + BlockVector3 pos = iterator.next(); + T obj = objectResolver.apply(pos); + char ordinal = ordinalResolver.apply(obj); + char value = palette[ordinal]; + if (value == Character.MAX_VALUE) { + palette[ordinal] = value = (char) index++; + if (index >= palette.length) { + throw new IOException("insufficient palette capacity: " + palette.length + ", index: " + index); + } + out.writeNamedTag(paletteEntryResolver.apply(obj), value); + } + if ((value & -128) != 0) { + dataBytesUsed++; + dataOut.write(value & 127 | 128); + value >>>= 7; + } + dataOut.write(value); + dataBytesUsed++; + } + // End Palette tag + out.write(NBTConstants.TYPE_END); + dataOut.finish(); + } finally { + // Write Data tag + if (dataBytesUsed > 0) { + try (LZ4BlockInputStream reader = new LZ4BlockInputStream(new ByteArrayInputStream(bytes.toByteArray()))) { + out.writeNamedTagName("Data", NBTConstants.TYPE_BYTE_ARRAY); + out.writeInt(dataBytesUsed); + IOUtil.copy(reader, (DataOutput) out); + } + } + } + } + + private void writeMetadata(NBTOutputStream metadata, Clipboard clipboard) throws IOException { + metadata.writeNamedTag("Date", System.currentTimeMillis()); + metadata.writeLazyCompoundTag("WorldEdit", out -> { + out.writeNamedTag("Version", WorldEdit.getVersion()); + out.writeNamedTag( + "EditingPlatform", + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getId() + ); + out.writeNamedTag("Origin", new int[]{ + clipboard.getOrigin().x(), clipboard.getOrigin().y(), clipboard.getOrigin().z() + }); + out.writeLazyCompoundTag("Platforms", platforms -> { + for (final Platform platform : WorldEdit.getInstance().getPlatformManager().getPlatforms()) { + platforms.writeLazyCompoundTag(platform.getId(), p -> { + p.writeNamedTag("Name", platform.getPlatformName()); + p.writeNamedTag("Version", platform.getPlatformVersion()); + }); + } + }); + }); + } + + @Override + public void close() throws IOException { + this.outputStream.close(); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/io/VarIntStreamIterator.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/io/VarIntStreamIterator.java new file mode 100644 index 000000000..17f4b9f0a --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/io/VarIntStreamIterator.java @@ -0,0 +1,70 @@ +package com.fastasyncworldedit.core.internal.io; + +import java.io.IOException; +import java.io.InputStream; +import java.util.NoSuchElementException; +import java.util.PrimitiveIterator; + +/** + * Basically {@link com.sk89q.worldedit.internal.util.VarIntIterator} but backed by {@link java.io.InputStream} + */ +public class VarIntStreamIterator implements PrimitiveIterator.OfInt { + + private final InputStream parent; + private final int limit; + private int index; + private boolean hasNextInt; + private int nextInt; + + public VarIntStreamIterator(final InputStream parent, int limit) { + this.parent = parent; + this.limit = limit; + } + + @Override + public boolean hasNext() { + if (hasNextInt) { + return true; + } + if (index >= limit) { + return false; + } + + try { + nextInt = readNextInt(); + } catch (IOException e) { + throw new RuntimeException(e); + } + return hasNextInt = true; + } + + @Override + public int nextInt() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + hasNextInt = false; + return nextInt; + } + + + private int readNextInt() throws IOException { + int value = 0; + for (int bitsRead = 0; ; bitsRead += 7) { + if (index >= limit) { + throw new IllegalStateException("Ran out of bytes while reading VarInt (probably corrupted data)"); + } + byte next = (byte) this.parent.read(); + index++; + value |= (next & 0x7F) << bitsRead; + if (bitsRead > 7 * 5) { + throw new IllegalStateException("VarInt too big (probably corrupted data)"); + } + if ((next & 0x80) == 0) { + break; + } + } + return value; + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/CompressedSchematicTag.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/CompressedSchematicTag.java index e622b1501..3c569f913 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/CompressedSchematicTag.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/CompressedSchematicTag.java @@ -1,6 +1,6 @@ package com.fastasyncworldedit.core.jnbt; -import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriter; +import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriterV2; import com.fastasyncworldedit.core.internal.io.FastByteArrayOutputStream; import com.fastasyncworldedit.core.internal.io.FastByteArraysInputStream; import com.sk89q.jnbt.NBTOutputStream; @@ -21,7 +21,7 @@ public class CompressedSchematicTag extends CompressedCompoundTag { FastByteArrayOutputStream blocksOut = new FastByteArrayOutputStream(); try (LZ4BlockOutputStream lz4out = new LZ4BlockOutputStream(blocksOut)) { NBTOutputStream nbtOut = new NBTOutputStream(lz4out); - new FastSchematicWriter(nbtOut).write(getSource()); + new FastSchematicWriterV2(nbtOut).write(getSource()); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java index 806168327..080ab3bea 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java @@ -572,7 +572,7 @@ public final class NBTInputStream implements Closeable { * @return the tag * @throws IOException if an I/O error occurs. */ - private Tag readTagPayload(int type, int depth) throws IOException { + public Tag readTagPayload(int type, int depth) throws IOException { //FAWE - public switch (type) { case NBTConstants.TYPE_END: if (depth == 0) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java index 1fd9dda9a..8a57411d6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java @@ -19,28 +19,38 @@ package com.sk89q.worldedit.extent.clipboard.io; -import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReader; -import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriter; +import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV2; +import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV3; +import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriterV2; +import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriterV3; import com.fastasyncworldedit.core.extent.clipboard.io.schematic.MinecraftStructure; import com.fastasyncworldedit.core.extent.clipboard.io.schematic.PNGWriter; import com.fastasyncworldedit.core.internal.io.ResettableFileInputStream; import com.google.common.collect.ImmutableSet; -import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.NBTConstants; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTOutputStream; import com.sk89q.jnbt.NamedTag; -import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV1Reader; +import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV2Reader; +import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV2Writer; +import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Reader; +import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Writer; +import it.unimi.dsi.fastutil.io.FastBufferedInputStream; import org.anarres.parallelgzip.ParallelGZIPOutputStream; +import org.enginehub.linbus.stream.LinBinaryIO; +import org.enginehub.linbus.tree.LinRootEntry; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Locale; -import java.util.Map; import java.util.Set; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -48,23 +58,14 @@ import java.util.zip.GZIPOutputStream; /** * A collection of supported clipboard formats. */ +@SuppressWarnings("removal") //FAWE: suppress JNBT deprecations public enum BuiltInClipboardFormat implements ClipboardFormat { //FAWE start - register fast clipboard io - FAST("fast", "fawe", "sponge", "schem") { - @Override - public String getPrimaryFileExtension() { - return "schem"; - } - + FAST_V3("fast", "fawe", "schem") { @Override public ClipboardReader getReader(InputStream inputStream) throws IOException { - if (inputStream instanceof FileInputStream) { - inputStream = new ResettableFileInputStream((FileInputStream) inputStream); - } - BufferedInputStream buffered = new BufferedInputStream(inputStream); - NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered))); - return new FastSchematicReader(nbtStream); + return new FastSchematicReaderV3(inputStream); } @Override @@ -77,13 +78,77 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { gzip = new ParallelGZIPOutputStream(outputStream); } NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip)); - return new FastSchematicWriter(nbtStream); + return new FastSchematicWriterV3(nbtStream); } @Override - public boolean isFormat(File file) { - String name = file.getName().toLowerCase(Locale.ROOT); - return name.endsWith(".schem") || name.endsWith(".sponge"); + public boolean isFormat(final InputStream inputStream) { + try (final DataInputStream stream = new DataInputStream(new FastBufferedInputStream(new GZIPInputStream(inputStream))); + final NBTInputStream nbt = new NBTInputStream(stream)) { + if (stream.readByte() != NBTConstants.TYPE_COMPOUND) { + return false; + } + stream.skipNBytes(2); // TAG name length ("" = 0), no need to read name as no bytes are written for root tag + if (stream.readByte() != NBTConstants.TYPE_COMPOUND) { + return false; + } + stream.skipNBytes(2); // TAG name length ("Schematic" = 9) + stream.skipNBytes(9); // "Schematic" + + // We can't guarantee the specific order of nbt data, so scan and skip, if required + do { + byte type = stream.readByte(); + String name = stream.readUTF(); + if (type == NBTConstants.TYPE_END) { + return false; + } + if (type == NBTConstants.TYPE_INT && name.equals("Version")) { + return stream.readInt() == FastSchematicWriterV3.CURRENT_VERSION; + } + nbt.readTagPayloadLazy(type, 0); + } while (true); + } catch (IOException ignored) { + } + return false; + } + + @Override + public String getPrimaryFileExtension() { + return "schem"; + } + }, + FAST_V2("fast.2", "fawe.2", "schem.2") { + @Override + public String getPrimaryFileExtension() { + return "schem"; + } + + @Override + public ClipboardReader getReader(InputStream inputStream) throws IOException { + if (inputStream instanceof FileInputStream) { + inputStream = new ResettableFileInputStream((FileInputStream) inputStream); + } + BufferedInputStream buffered = new BufferedInputStream(inputStream); + NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered))); + return new FastSchematicReaderV2(nbtStream); + } + + @Override + public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { + OutputStream gzip; + if (outputStream instanceof ParallelGZIPOutputStream || outputStream instanceof GZIPOutputStream) { + gzip = outputStream; + } else { + outputStream = new BufferedOutputStream(outputStream); + gzip = new ParallelGZIPOutputStream(outputStream); + } + NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip)); + return new FastSchematicWriterV2(nbtStream); + } + + @Override + public boolean isFormat(InputStream inputStream) { + return detectOldSpongeSchematic(inputStream, FastSchematicWriterV2.CURRENT_VERSION); } }, @@ -113,9 +178,39 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { } @Override - public boolean isFormat(File file) { - String name = file.getName().toLowerCase(Locale.ROOT); - return name.endsWith(".schematic") || name.endsWith(".mcedit") || name.endsWith(".mce"); + public boolean isFormat(InputStream inputStream) { + LinRootEntry rootEntry; + try { + DataInputStream stream = new DataInputStream(new GZIPInputStream(inputStream)); + rootEntry = LinBinaryIO.readUsing(stream, LinRootEntry::readFrom); + } catch (Exception e) { + return false; + } + if (!rootEntry.name().equals("Schematic")) { + return false; + } + return rootEntry.value().value().containsKey("Materials"); + } + }, + SPONGE_V1_SCHEMATIC("sponge.1") { + @Override + public String getPrimaryFileExtension() { + return "schem"; + } + + @Override + public ClipboardReader getReader(InputStream inputStream) throws IOException { + return new SpongeSchematicV1Reader(LinBinaryIO.read(new DataInputStream(new GZIPInputStream(inputStream)))); + } + + @Override + public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { + throw new IOException("This format does not support saving"); + } + + @Override + public boolean isFormat(InputStream inputStream) { + return detectOldSpongeSchematic(inputStream, 1); } }, @@ -125,7 +220,8 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { * Avoid using with any large schematics/clipboards for reading/writing. */ @Deprecated - SPONGE_SCHEMATIC("slow", "safe") { + SPONGE_V2_SCHEMATIC("slow.2", "safe.2", "sponge.2") { // FAWE - edit aliases for fast + @Override public String getPrimaryFileExtension() { return "schem"; @@ -133,38 +229,43 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { @Override public ClipboardReader getReader(InputStream inputStream) throws IOException { - NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(inputStream)); - return new SpongeSchematicReader(nbtStream); + return new SpongeSchematicV2Reader(LinBinaryIO.read(new DataInputStream(new GZIPInputStream(inputStream)))); } @Override public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { - NBTOutputStream nbtStream = new NBTOutputStream(new GZIPOutputStream(outputStream)); - return new SpongeSchematicWriter(nbtStream); + return new SpongeSchematicV2Writer(new DataOutputStream(new GZIPOutputStream(outputStream))); + } + + @Override + public boolean isFormat(InputStream inputStream) { + return detectOldSpongeSchematic(inputStream, 2); + } + }, + SPONGE_V3_SCHEMATIC("sponge.3", "slow", "safe") { // FAWE - edit aliases for fast + + @Override + public String getPrimaryFileExtension() { + return "schem"; + } + + @Override + public ClipboardReader getReader(InputStream inputStream) throws IOException { + return new SpongeSchematicV3Reader(LinBinaryIO.read(new DataInputStream(new GZIPInputStream(inputStream)))); + } + + @Override + public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { + return new SpongeSchematicV3Writer(new DataOutputStream(new GZIPOutputStream(outputStream))); } @Override public boolean isFormat(File file) { - try (NBTInputStream str = new NBTInputStream(new GZIPInputStream(new FileInputStream(file)))) { - NamedTag rootTag = str.readNamedTag(); - if (!rootTag.getName().equals("Schematic")) { - return false; - } - CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); - - // Check - Map> schematic = schematicTag.getValue(); - if (!schematic.containsKey("Version")) { - return false; - } - } catch (Exception e) { - return false; - } - - return true; + //FAWE start - delegate to stream-based isFormat approach of fast impl + return FAST_V3.isFormat(file); + //FAWE end } }, - //FAWE start - recover schematics with bad entity data & register other clipboard formats BROKENENTITY("brokenentity", "legacyentity", "le", "be", "brokenentities", "legacyentities") { @Override @@ -179,7 +280,7 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { } BufferedInputStream buffered = new BufferedInputStream(inputStream); NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered))); - FastSchematicReader reader = new FastSchematicReader(nbtStream); + FastSchematicReaderV2 reader = new FastSchematicReaderV2(nbtStream); reader.setBrokenEntities(true); return reader; } @@ -194,7 +295,7 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { gzip = new ParallelGZIPOutputStream(outputStream); } NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip)); - FastSchematicWriter writer = new FastSchematicWriter(nbtStream); + FastSchematicWriterV2 writer = new FastSchematicWriterV2(nbtStream); writer.setBrokenEntities(true); return writer; } @@ -232,9 +333,37 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { } @Override - public boolean isFormat(File file) { - String name = file.getName().toLowerCase(Locale.ROOT); - return name.endsWith(".nbt"); + public boolean isFormat(InputStream inputStream) { + try (final DataInputStream stream = new DataInputStream(new FastBufferedInputStream(new GZIPInputStream(inputStream))); + final NBTInputStream nbt = new NBTInputStream(stream)) { + if (stream.readByte() != NBTConstants.TYPE_COMPOUND) { + return false; + } + NamedTag namedTag = nbt.readNamedTag(); + if (!namedTag.getName().isEmpty()) { + return false; + } + + // We can't guarantee the specific order of nbt data, so scan and skip, if required + do { + byte type = stream.readByte(); + String name = stream.readUTF(); + if (type == NBTConstants.TYPE_END) { + return false; + } + if (type == NBTConstants.TYPE_LIST && name.equals("size")) { + return true; + } + nbt.readTagPayloadLazy(type, 0); + } while (true); + } catch (IOException ignored) { + } + return false; + } + + @Override + public boolean isFormat(final File file) { + return file.getName().toLowerCase(Locale.ROOT).endsWith(".nbt") && super.isFormat(file); } }, @@ -265,6 +394,53 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { }; //FAWE end + private static boolean detectOldSpongeSchematic(InputStream inputStream, int version) { + //FAWE start - dont utilize linbus - WorldEdit approach is not really streamed + try (final DataInputStream stream = new DataInputStream(new FastBufferedInputStream(new GZIPInputStream(inputStream))); + final NBTInputStream nbt = new NBTInputStream(stream)) { + if (stream.readByte() != NBTConstants.TYPE_COMPOUND) { + return false; + } + stream.skipNBytes(2); // TAG name length ("Schematic" = 9) + stream.skipNBytes(9); // "Schematic" + + // We can't guarantee the specific order of nbt data, so scan and skip, if required + do { + byte type = stream.readByte(); + String name = stream.readUTF(); + if (type == NBTConstants.TYPE_END) { + return false; + } + if (type == NBTConstants.TYPE_INT && name.equals("Version")) { + return stream.readInt() == version; + } + nbt.readTagPayloadLazy(type, 0); + } while (true); + } catch (IOException ignored) { + } + return false; + } + + /** + * For backwards compatibility, this points to the Sponge Schematic Specification (Version 2) + * format. This should not be used going forwards. + * + * @deprecated Use {@link #SPONGE_V2_SCHEMATIC} or {@link #SPONGE_V3_SCHEMATIC} + */ + @Deprecated + public static final BuiltInClipboardFormat SPONGE_SCHEMATIC = SPONGE_V2_SCHEMATIC; + + //FAWE start + /** + * For backwards compatibility, this points to the fast implementation of the Sponge Schematic Specification (Version 2) + * format. This should not be used going forwards. + * + * @deprecated Use {@link #FAST_V2} or {@link #FAST_V3} + */ + @Deprecated + public static final BuiltInClipboardFormat FAST = FAST_V2; + //FAWE end + private final ImmutableSet aliases; BuiltInClipboardFormat(String... aliases) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java index cb5cd1b7a..7b4b1bf3b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java @@ -35,6 +35,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.URI; import java.net.URL; +import java.nio.file.Files; import java.util.Set; import static com.google.common.base.Preconditions.checkNotNull; @@ -82,7 +83,29 @@ public interface ClipboardFormat { * @param file the file * @return true if the given file is of this format */ - boolean isFormat(File file); + default boolean isFormat(File file) { + try (InputStream stream = Files.newInputStream(file.toPath())) { + return isFormat(stream); + } catch (IOException e) { + return false; + } + } + + /** + * Return whether the given stream is of this format. + * + * @apiNote The caller is responsible for the following: + *

      + *
    • Closing the input stream
    • + *
    + * + * @param inputStream The stream + * @return true if the given stream is of this format + * @since TODO + */ + default boolean isFormat(InputStream inputStream) { + return false; + } /** * Get the file extension this format primarily uses. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java index a6b9c1400..017f07e9c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.extent.clipboard.io; import com.sk89q.jnbt.Tag; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; import java.io.IOException; @@ -27,7 +28,10 @@ import java.util.Map; /** * Base class for NBT schematic readers. + * + * @deprecated These utility methods are provided by {@link LinCompoundTag} now. */ +@Deprecated public abstract class NBTSchematicReader implements ClipboardReader { protected static > T requireTag(Map> items, String key, Class expected) throws IOException { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicNbtUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicNbtUtil.java new file mode 100644 index 000000000..7da0aa164 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicNbtUtil.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 General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io; + +import com.sk89q.jnbt.Tag; + +import java.io.IOException; +import java.util.Map; +import javax.annotation.Nullable; + +// note, when clearing deprecations these methods don't need to remain -- they're introduced in 7.3.0 +public class SchematicNbtUtil { + public static T requireTag(Map items, String key, Class expected) throws IOException { + if (!items.containsKey(key)) { + throw new IOException("Schematic file is missing a \"" + key + "\" tag of type " + + expected.getName()); + } + + Tag tag = items.get(key); + if (!expected.isInstance(tag)) { + throw new IOException(key + " tag is not of tag type " + expected.getName() + ", got " + + tag.getClass().getName() + " instead"); + } + + return expected.cast(tag); + } + + @Nullable + public static T getTag(Map items, String key, Class expected) { + if (!items.containsKey(key)) { + return null; + } + + Tag test = items.get(key); + if (!expected.isInstance(test)) { + return null; + } + + return expected.cast(test); + } + + private SchematicNbtUtil() { + } +} 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 deleted file mode 100644 index ec82be228..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java +++ /dev/null @@ -1,453 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.extent.clipboard.io; - -import com.fastasyncworldedit.core.configuration.Caption; -import com.google.common.collect.Maps; -import com.sk89q.jnbt.LinBusConverter; -import com.sk89q.jnbt.ByteArrayTag; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.IntArrayTag; -import com.sk89q.jnbt.IntTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.NBTInputStream; -import com.sk89q.jnbt.NamedTag; -import com.sk89q.jnbt.ShortTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.extension.input.InputParseException; -import com.sk89q.worldedit.extension.input.ParserContext; -import com.sk89q.worldedit.extension.platform.Capability; -import com.sk89q.worldedit.extension.platform.Platform; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; -import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.internal.Constants; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.formatting.text.TextComponent; -import com.sk89q.worldedit.world.DataFixer; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.BiomeTypes; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.entity.EntityType; -import com.sk89q.worldedit.world.entity.EntityTypes; -import com.sk89q.worldedit.world.storage.NBTConversions; -import org.apache.logging.log4j.Logger; - -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.OptionalInt; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Reads schematic files using the Sponge Schematic Specification. - * - * @deprecated Slow, resource intensive, but sometimes safer than using the recommended - * {@link com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReader}. - * Avoid reading large schematics with this reader. - */ -@Deprecated -public class SpongeSchematicReader extends NBTSchematicReader { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - private final NBTInputStream inputStream; - private DataFixer fixer = null; - private int schematicVersion = -1; - private int dataVersion = -1; - - /** - * Create a new instance. - * - * @param inputStream the input stream to read from - */ - public SpongeSchematicReader(NBTInputStream inputStream) { - checkNotNull(inputStream); - this.inputStream = inputStream; - } - - @Override - 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 = Constants.DATA_VERSION_MC_1_13_2; // 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 < 0) { - LOGGER.warn( - "Schematic has an unknown data version ({}). Data may be incompatible.", - dataVersion - ); - // Do not DFU unknown data - dataVersion = liveDataVersion; - } - if (dataVersion > liveDataVersion) { - LOGGER.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) { - LOGGER.info("Schematic was made in an older Minecraft version ({} < {}), will attempt DFU.", - dataVersion, liveDataVersion - ); - } else { - LOGGER.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 SchematicLoadException(Caption.of("worldedit.schematic.load.unsupported-version", - TextComponent.of(schematicVersion))); - } - - @Override - public OptionalInt getDataVersion() { - try { - CompoundTag schematicTag = getBaseTag(); - Map> schematic = schematicTag.getValue(); - if (schematicVersion == 1) { - return OptionalInt.of(Constants.DATA_VERSION_MC_1_13_2); - } else if (schematicVersion == 2) { - int dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue(); - if (dataVersion < 0) { - return OptionalInt.empty(); - } - return OptionalInt.of(dataVersion); - } - return OptionalInt.empty(); - } catch (IOException e) { - return OptionalInt.empty(); - } - } - - private CompoundTag getBaseTag() throws IOException { - NamedTag rootTag = inputStream.readNamedTag(); - CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); - - // Check - Map> schematic = schematicTag.getValue(); - - // Be lenient about the specific nesting level of the Schematic tag - // Also allows checking the version from newer versions of the specification - if (schematic.size() == 1 && schematic.containsKey("Schematic")) { - schematicTag = requireTag(schematic, "Schematic", CompoundTag.class); - schematic = schematicTag.getValue(); - } - - schematicVersion = requireTag(schematic, "Version", IntTag.class).getValue(); - return schematicTag; - } - - private BlockArrayClipboard readVersion1(CompoundTag schematicTag) throws IOException { - BlockVector3 origin; - Region region; - Map> schematic = schematicTag.getValue(); - - int width = requireTag(schematic, "Width", ShortTag.class).getValue(); - int height = requireTag(schematic, "Height", ShortTag.class).getValue(); - int length = requireTag(schematic, "Length", ShortTag.class).getValue(); - - IntArrayTag offsetTag = getTag(schematic, "Offset", IntArrayTag.class); - int[] offsetParts; - if (offsetTag != null) { - offsetParts = offsetTag.getValue(); - if (offsetParts.length != 3) { - throw new IOException("Invalid offset specified in schematic."); - } - } else { - offsetParts = new int[]{0, 0, 0}; - } - - BlockVector3 min = BlockVector3.at(offsetParts[0], offsetParts[1], offsetParts[2]); - - CompoundTag metadataTag = getTag(schematic, "Metadata", CompoundTag.class); - if (metadataTag != null && metadataTag.containsKey("WEOffsetX")) { - // We appear to have WorldEdit Metadata - Map> metadata = metadataTag.getValue(); - int offsetX = requireTag(metadata, "WEOffsetX", IntTag.class).getValue(); - int offsetY = requireTag(metadata, "WEOffsetY", IntTag.class).getValue(); - int offsetZ = requireTag(metadata, "WEOffsetZ", IntTag.class).getValue(); - BlockVector3 offset = BlockVector3.at(offsetX, offsetY, offsetZ); - origin = min.subtract(offset); - region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE)); - } else { - origin = min; - region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE)); - } - - IntTag paletteMaxTag = getTag(schematic, "PaletteMax", IntTag.class); - Map> paletteObject = requireTag(schematic, "Palette", CompoundTag.class).getValue(); - if (paletteMaxTag != null && paletteObject.size() != paletteMaxTag.getValue()) { - throw new IOException("Block palette size does not match expected size."); - } - - Map palette = new HashMap<>(); - - ParserContext parserContext = new ParserContext(); - parserContext.setRestricted(false); - parserContext.setTryLegacy(false); - parserContext.setPreferringWildcard(false); - - for (String palettePart : paletteObject.keySet()) { - int id = requireTag(paletteObject, palettePart, IntTag.class).getValue(); - if (fixer != null) { - palettePart = fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, palettePart, dataVersion); - } - BlockState state; - try { - state = WorldEdit.getInstance().getBlockFactory().parseFromInput(palettePart, parserContext).toImmutableState(); - } catch (InputParseException e) { - LOGGER.warn("Invalid BlockState in palette: " + palettePart + ". Block will be replaced with air."); - state = BlockTypes.AIR.getDefaultState(); - } - palette.put(id, state); - } - - byte[] blocks = requireTag(schematic, "BlockData", ByteArrayTag.class).getValue(); - - Map>> tileEntitiesMap = new HashMap<>(); - ListTag tileEntities = getTag(schematic, "BlockEntities", ListTag.class); - if (tileEntities == null) { - tileEntities = getTag(schematic, "TileEntities", ListTag.class); - } - if (tileEntities != null) { - for (Object tileTag : tileEntities.getValue()) { - Map> tileEntity = ((CompoundTag) tileTag).getValue(); - int[] pos = requireTag(tileEntity, "Pos", IntArrayTag.class).getValue(); - final BlockVector3 pt = BlockVector3.at(pos[0], pos[1], pos[2]); - Map> values = Maps.newHashMap(tileEntity); - values.put("x", new IntTag(pt.x())); - values.put("y", new IntTag(pt.y())); - values.put("z", new IntTag(pt.z())); - //FAWE start - support old, corrupt schematics - Tag id = values.get("Id"); - if (id == null) { - id = values.get("id"); - } - if (id == null) { - continue; - } - values.put("id", id); - //FAWE end - values.remove("Id"); - values.remove("Pos"); - if (fixer != null) { - //FAWE start - LinTag - tileEntity = ((CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp( - DataFixer.FixTypes.BLOCK_ENTITY, - new CompoundTag(values).toLinTag(), - dataVersion - ))).getValue(); - //FAWE end - } else { - tileEntity = values; - } - tileEntitiesMap.put(pt, tileEntity); - } - } - - BlockArrayClipboard clipboard = new BlockArrayClipboard(region); - clipboard.setOrigin(origin); - - int index = 0; - int i = 0; - int value; - int varintLength; - while (i < blocks.length) { - value = 0; - varintLength = 0; - - while (true) { - value |= (blocks[i] & 127) << (varintLength++ * 7); - if (varintLength > 5) { - throw new IOException("VarInt too big (probably corrupted data)"); - } - if ((blocks[i] & 128) != 128) { - i++; - break; - } - i++; - } - // index = (y * length * width) + (z * width) + x - int y = index / (width * length); - int z = (index % (width * length)) / width; - int x = (index % (width * length)) % width; - BlockState state = palette.get(value); - BlockVector3 pt = BlockVector3.at(x, y, z); - try { - if (tileEntitiesMap.containsKey(pt)) { - clipboard.setBlock( - clipboard.getMinimumPoint().add(pt), - state.toBaseBlock(new CompoundTag(tileEntitiesMap.get(pt))) - ); - } else { - clipboard.setBlock(clipboard.getMinimumPoint().add(pt), state); - } - } catch (WorldEditException e) { - throw new IOException("Failed to load a block in the schematic"); - } - - index++; - } - - 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) { - LOGGER.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().x(); - - byte[] biomes = dataTag.getValue(); - int biomeIndex = 0; - int biomeJ = 0; - int bVal; - int varIntLength; - BlockVector3 min = clipboard.getMinimumPoint(); - 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); - for (int y = 0; y < clipboard.getRegion().getHeight(); y++) { - clipboard.setBiome(min.add(x, y, 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) { - //FAWE start - LinTag - entityTag = (CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp( - DataFixer.FixTypes.ENTITY, - entityTag.toLinTag(), - dataVersion - )); - //FAWE end - } - - 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 { - LOGGER.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/share/BuiltInClipboardShareDestinations.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/BuiltInClipboardShareDestinations.java index 981debe4b..551ac5dd7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/BuiltInClipboardShareDestinations.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/BuiltInClipboardShareDestinations.java @@ -61,7 +61,7 @@ public enum BuiltInClipboardShareDestinations implements ClipboardShareDestinati PasteMetadata pasteMetadata = new PasteMetadata(); pasteMetadata.author = metadata.author(); - pasteMetadata.extension = "schem"; + pasteMetadata.extension = metadata.format().getPrimaryFileExtension(); pasteMetadata.name = metadata.name(); EngineHubPaste pasteService = new EngineHubPaste(); @@ -75,7 +75,7 @@ public enum BuiltInClipboardShareDestinations implements ClipboardShareDestinati @Override public ClipboardFormat getDefaultFormat() { - return BuiltInClipboardFormat.SPONGE_SCHEMATIC; + return BuiltInClipboardFormat.SPONGE_V2_SCHEMATIC; } @Override @@ -119,13 +119,14 @@ public enum BuiltInClipboardShareDestinations implements ClipboardShareDestinati @Override public ClipboardFormat getDefaultFormat() { - return BuiltInClipboardFormat.FAST; + return BuiltInClipboardFormat.FAST_V3; } @Override public boolean supportsFormat(final ClipboardFormat format) { - return format == BuiltInClipboardFormat.SPONGE_SCHEMATIC || - format == BuiltInClipboardFormat.FAST || + return format == BuiltInClipboardFormat.SPONGE_V2_SCHEMATIC || + format == BuiltInClipboardFormat.FAST_V3 || + format == BuiltInClipboardFormat.FAST_V2 || format == BuiltInClipboardFormat.MCEDIT_SCHEMATIC; } }; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/ReaderUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/ReaderUtil.java new file mode 100644 index 000000000..5c4e90264 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/ReaderUtil.java @@ -0,0 +1,283 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.sponge; + + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.internal.util.VarIntIterator; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.storage.NBTConversions; +import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTagType; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkState; + +/** + * Common code shared between schematic readers. + */ +public class ReaderUtil { //FAWE - make public + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + static void checkSchematicVersion(int version, LinCompoundTag schematicTag) throws IOException { + int schematicVersion = getSchematicVersion(schematicTag); + + checkState( + version == schematicVersion, + "Schematic is not version %s, but %s", version, schematicVersion + ); + } + + public static int getSchematicVersion(LinCompoundTag schematicTag) throws IOException { + return schematicTag.getTag("Version", LinTagType.intTag()).valueAsInt(); + } + + static VersionedDataFixer getVersionedDataFixer( + LinCompoundTag schematic, Platform platform, + int liveDataVersion + ) { + //FAWE start - call fawe method without NBT component requirement + return getVersionedDataFixer(schematic.getTag("DataVersion", LinTagType.intTag()).valueAsInt(), platform, + liveDataVersion + ); + //FAWE end + } + + //FAWE start - make getVersionedDataFixer without schematic compound + public + public static VersionedDataFixer getVersionedDataFixer(int schematicDataVersion, Platform platform, int liveDataVersion) { + DataFixer fixer = null; + if (schematicDataVersion < 0) { + LOGGER.warn( + "Schematic has an unknown data version ({}). Data may be incompatible.", + schematicDataVersion + ); + } else if (schematicDataVersion > liveDataVersion) { + LOGGER.warn( + "Schematic was made in a newer Minecraft version ({} > {})." + + " Data may be incompatible.", + schematicDataVersion, liveDataVersion + ); + } else if (schematicDataVersion < liveDataVersion) { + fixer = platform.getDataFixer(); + if (fixer != null) { + LOGGER.debug( + "Schematic was made in an older Minecraft version ({} < {})," + + " will attempt DFU.", + schematicDataVersion, liveDataVersion + ); + } else { + LOGGER.info( + "Schematic was made in an older Minecraft version ({} < {})," + + " but DFU is not available. Data may be incompatible.", + schematicDataVersion, liveDataVersion + ); + } + } + return new VersionedDataFixer(schematicDataVersion, fixer); + } + //FAWE end + + static Map decodePalette( + LinCompoundTag paletteObject, VersionedDataFixer fixer + ) throws IOException { + Map palette = new HashMap<>(); + + ParserContext parserContext = new ParserContext(); + parserContext.setRestricted(false); + parserContext.setTryLegacy(false); + parserContext.setPreferringWildcard(false); + + for (var palettePart : paletteObject.value().entrySet()) { + if (!(palettePart.getValue() instanceof LinIntTag idTag)) { + throw new IOException("Invalid palette entry: " + palettePart); + } + int id = idTag.valueAsInt(); + String paletteName = fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, palettePart.getKey()); + BlockState state; + try { + state = WorldEdit.getInstance().getBlockFactory().parseFromInput(paletteName, parserContext).toImmutableState(); + } catch (InputParseException e) { + LOGGER.warn("Invalid BlockState in palette: " + palettePart + ". Block will be replaced with air."); + state = BlockTypes.AIR.getDefaultState(); + } + palette.put(id, state); + } + return palette; + } + + static void initializeClipboardFromBlocks( + Clipboard clipboard, Map palette, byte[] blocks, LinListTag tileEntities, + VersionedDataFixer fixer, boolean dataIsNested + ) throws IOException { + Map tileEntitiesMap = new HashMap<>(); + if (tileEntities != null) { + for (LinCompoundTag tileEntity : tileEntities.value()) { + final BlockVector3 pt = clipboard.getMinimumPoint().add( + decodeBlockVector3(tileEntity.getTag("Pos", LinTagType.intArrayTag())) + ); + LinCompoundTag.Builder values = extractData(dataIsNested, tileEntity); + values.putInt("x", pt.x()); + values.putInt("y", pt.y()); + values.putInt("z", pt.z()); + values.put("id", tileEntity.value().get("Id")); + if (fixer.isActive()) { + tileEntity = fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, values.build()); + } else { + tileEntity = values.build(); + } + tileEntitiesMap.put(pt, tileEntity); + } + } + + int width = clipboard.getRegion().getWidth(); + int length = clipboard.getRegion().getLength(); + + int index = 0; + for (VarIntIterator iter = new VarIntIterator(blocks); iter.hasNext(); index++) { + int nextBlockId = iter.nextInt(); + BlockState state = palette.get(nextBlockId); + BlockVector3 rawPos = decodePositionFromDataIndex(width, length, index); + try { + BlockVector3 offsetPos = clipboard.getMinimumPoint().add(rawPos); + LinCompoundTag tileEntity = tileEntitiesMap.get(offsetPos); + clipboard.setBlock(offsetPos, state.toBaseBlock(tileEntity)); + } catch (WorldEditException e) { + throw new IOException("Failed to load a block in the schematic", e); + } + } + } + + private static LinCompoundTag.Builder extractData(boolean dataIsNested, LinCompoundTag tag) { + if (dataIsNested) { + LinCompoundTag dataTag = tag.findTag("Data", LinTagType.compoundTag()); + return dataTag != null ? dataTag.toBuilder() : LinCompoundTag.builder(); + } else { + LinCompoundTag.Builder values = tag.toBuilder(); + values.remove("Id"); + values.remove("Pos"); + return values; + } + } + + static BlockVector3 decodePositionFromDataIndex(int width, int length, int index) { + // index = (y * width * length) + (z * width) + x + int y = index / (width * length); + int remainder = index - (y * width * length); + int z = remainder / width; + int x = remainder - z * width; + return BlockVector3.at(x, y, z); + } + + static BlockVector3 decodeBlockVector3(@Nullable LinIntArrayTag tag) throws IOException { + if (tag == null) { + return BlockVector3.ZERO; + } + int[] parts = tag.value(); + if (parts.length != 3) { + throw new IOException("Invalid block vector specified in schematic."); + } + return BlockVector3.at(parts[0], parts[1], parts[2]); + } + + static void readEntities( + BlockArrayClipboard clipboard, List entList, + VersionedDataFixer fixer, boolean positionIsRelative + ) { + if (entList.isEmpty()) { + return; + } + for (LinCompoundTag entityTag : entList) { + String id = entityTag.getTag("Id", LinTagType.stringTag()).value(); + LinCompoundTag.Builder values = extractData(positionIsRelative, entityTag); + LinCompoundTag dataTag = values.putString("id", id).build(); + dataTag = fixer.fixUp(DataFixer.FixTypes.ENTITY, dataTag); + + EntityType entityType = EntityTypes.get(id); + if (entityType != null) { + Location location = NBTConversions.toLocation( + clipboard, + entityTag.getListTag("Pos", LinTagType.doubleTag()), + dataTag.getListTag("Rotation", LinTagType.floatTag()) + ); + BaseEntity state = new BaseEntity(entityType, LazyReference.computed(dataTag)); + if (positionIsRelative) { + location = location.setPosition( + location.toVector().add(clipboard.getMinimumPoint().toVector3()) + ); + } + clipboard.createEntity(location, state); + } else { + LOGGER.warn("Unknown entity when pasting schematic: " + id); + } + } + } + + static Int2ObjectMap readBiomePalette(VersionedDataFixer fixer, LinCompoundTag paletteTag, Logger logger) throws + IOException { + Int2ObjectMap palette = new Int2ObjectLinkedOpenHashMap<>(paletteTag.value().size()); + for (var palettePart : paletteTag.value().entrySet()) { + String key = palettePart.getKey(); + key = fixer.fixUp(DataFixer.FixTypes.BIOME, key); + BiomeType biome = BiomeTypes.get(key); + if (biome == null) { + logger.warn("Unknown biome type :" + key + + " in palette. Are you missing a mod or using a schematic made in a newer version of Minecraft?"); + } + if (!(palettePart.getValue() instanceof LinIntTag idTag)) { + throw new IOException("Biome mapped to non-Int tag."); + } + palette.put(idTag.valueAsInt(), biome); + } + return palette; + } + + private ReaderUtil() { + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV1Reader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV1Reader.java new file mode 100644 index 000000000..7574bfe4c --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV1Reader.java @@ -0,0 +1,134 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.sponge; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.block.BlockState; +import org.enginehub.linbus.stream.LinStream; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinRootEntry; +import org.enginehub.linbus.tree.LinTagType; + +import java.io.IOException; +import java.util.Map; +import java.util.OptionalInt; + +/** + * Reads schematic files using the Sponge Schematic Specification (Version 1). + */ +public class SpongeSchematicV1Reader implements ClipboardReader { + + private final LinStream rootStream; + + public SpongeSchematicV1Reader(LinStream rootStream) { + this.rootStream = rootStream; + } + + @Override + public Clipboard read() throws IOException { + LinCompoundTag schematicTag = getBaseTag(); + ReaderUtil.checkSchematicVersion(1, schematicTag); + + return doRead(schematicTag); + } + + // For legacy SpongeSchematicReader, can be inlined in WorldEdit 8 + public static BlockArrayClipboard doRead(LinCompoundTag schematicTag) throws IOException { + final Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING); + + // this is a relatively safe assumption unless someone imports a schematic from 1.12 + // e.g. sponge 7.1- + VersionedDataFixer fixer = new VersionedDataFixer(Constants.DATA_VERSION_MC_1_13_2, platform.getDataFixer()); + return readVersion1(schematicTag, fixer); + } + + @Override + public OptionalInt getDataVersion() { + try { + // Validate schematic version to be sure + ReaderUtil.checkSchematicVersion(1, getBaseTag()); + return OptionalInt.of(Constants.DATA_VERSION_MC_1_13_2); + } catch (IOException e) { + return OptionalInt.empty(); + } + } + + private LinCompoundTag getBaseTag() throws IOException { + return LinRootEntry.readFrom(rootStream).value(); + } + + static BlockArrayClipboard readVersion1(LinCompoundTag schematicTag, VersionedDataFixer fixer) throws IOException { + int width = schematicTag.getTag("Width", LinTagType.shortTag()).valueAsShort() & 0xFFFF; + int height = schematicTag.getTag("Height", LinTagType.shortTag()).valueAsShort() & 0xFFFF; + int length = schematicTag.getTag("Length", LinTagType.shortTag()).valueAsShort() & 0xFFFF; + + BlockVector3 min = ReaderUtil.decodeBlockVector3(schematicTag.findTag("Offset", LinTagType.intArrayTag())); + + BlockVector3 offset = BlockVector3.ZERO; + LinCompoundTag metadataTag = schematicTag.findTag("Metadata", LinTagType.compoundTag()); + if (metadataTag != null) { + LinIntTag offsetX = metadataTag.findTag("WEOffsetX", LinTagType.intTag()); + if (offsetX != null) { + int offsetY = metadataTag.getTag("WEOffsetY", LinTagType.intTag()).valueAsInt(); + int offsetZ = metadataTag.getTag("WEOffsetZ", LinTagType.intTag()).valueAsInt(); + offset = BlockVector3.at(offsetX.valueAsInt(), offsetY, offsetZ); + } + } + + BlockVector3 origin = min.subtract(offset); + Region region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE)); + + LinIntTag paletteMaxTag = schematicTag.findTag("PaletteMax", LinTagType.intTag()); + LinCompoundTag paletteObject = schematicTag.getTag("Palette", LinTagType.compoundTag()); + if (paletteMaxTag != null && paletteObject.value().size() != paletteMaxTag.valueAsInt()) { + throw new IOException("Block palette size does not match expected size."); + } + + Map palette = ReaderUtil.decodePalette(paletteObject, fixer); + + byte[] blocks = schematicTag.getTag("BlockData", LinTagType.byteArrayTag()).value(); + + LinListTag tileEntities = schematicTag.findListTag("BlockEntities", LinTagType.compoundTag()); + if (tileEntities == null) { + tileEntities = schematicTag.findListTag("TileEntities", LinTagType.compoundTag()); + } + + BlockArrayClipboard clipboard = new BlockArrayClipboard(region); + clipboard.setOrigin(origin); + ReaderUtil.initializeClipboardFromBlocks(clipboard, palette, blocks, tileEntities, fixer, false); + return clipboard; + } + + @Override + public void close() throws IOException { + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV2Reader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV2Reader.java new file mode 100644 index 000000000..2cd7bb1e1 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV2Reader.java @@ -0,0 +1,144 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.sponge; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.internal.util.VarIntIterator; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.stream.LinStream; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinRootEntry; +import org.enginehub.linbus.tree.LinTagType; + +import java.io.IOException; +import java.util.OptionalInt; + +/** + * Reads schematic files using the Sponge Schematic Specification (Version 2). + */ +public class SpongeSchematicV2Reader implements ClipboardReader { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private final LinStream rootStream; + + public SpongeSchematicV2Reader(LinStream rootStream) { + this.rootStream = rootStream; + } + + @Override + public Clipboard read() throws IOException { + LinCompoundTag schematicTag = getBaseTag(); + ReaderUtil.checkSchematicVersion(2, schematicTag); + + return doRead(schematicTag); + } + + // For legacy SpongeSchematicReader, can be inlined in WorldEdit 8 + public static Clipboard doRead(LinCompoundTag schematicTag) throws IOException { + final Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING); + int liveDataVersion = platform.getDataVersion(); + + VersionedDataFixer fixer = ReaderUtil.getVersionedDataFixer(schematicTag, platform, liveDataVersion); + BlockArrayClipboard clip = SpongeSchematicV1Reader.readVersion1(schematicTag, fixer); + return readVersion2(clip, schematicTag, fixer); + } + + @Override + public OptionalInt getDataVersion() { + try { + LinCompoundTag schematicTag = getBaseTag(); + ReaderUtil.checkSchematicVersion(2, schematicTag); + + int dataVersion = schematicTag.getTag("DataVersion", LinTagType.intTag()).valueAsInt(); + if (dataVersion < 0) { + return OptionalInt.empty(); + } + return OptionalInt.of(dataVersion); + } catch (IOException e) { + return OptionalInt.empty(); + } + } + + private LinCompoundTag getBaseTag() throws IOException { + return LinRootEntry.readFrom(rootStream).value(); + } + + private static Clipboard readVersion2( + BlockArrayClipboard version1, LinCompoundTag schematicTag, VersionedDataFixer fixer + ) throws IOException { + if (schematicTag.value().containsKey("BiomeData")) { + readBiomes2(version1, schematicTag, fixer); + } + LinListTag entities = schematicTag.findListTag("Entities", LinTagType.compoundTag()); + if (entities != null) { + ReaderUtil.readEntities(version1, entities.value(), fixer, false); + } + return version1; + } + + private static void readBiomes2( + BlockArrayClipboard clipboard, LinCompoundTag schematic, VersionedDataFixer fixer + ) throws IOException { + LinByteArrayTag dataTag = schematic.getTag("BiomeData", LinTagType.byteArrayTag()); + LinIntTag maxTag = schematic.getTag("BiomePaletteMax", LinTagType.intTag()); + LinCompoundTag paletteTag = schematic.getTag("BiomePalette", LinTagType.compoundTag()); + + if (maxTag.valueAsInt() != paletteTag.value().size()) { + throw new IOException("Biome palette size does not match expected size."); + } + + Int2ObjectMap palette = ReaderUtil.readBiomePalette(fixer, paletteTag, LOGGER); + + int width = clipboard.getDimensions().x(); + + byte[] biomes = dataTag.value(); + BlockVector3 min = clipboard.getMinimumPoint(); + int index = 0; + for (VarIntIterator iter = new VarIntIterator(biomes); iter.hasNext(); index++) { + int nextBiomeId = iter.nextInt(); + BiomeType type = palette.get(nextBiomeId); + // hack -- the x and y values from the 3d decode with length == 1 are equivalent + BlockVector3 hackDecode = ReaderUtil.decodePositionFromDataIndex(width, 1, index); + int x = hackDecode.x(); + int z = hackDecode.y(); + for (int y = 0; y < clipboard.getRegion().getHeight(); y++) { + clipboard.setBiome(min.add(x, y, z), type); + } + } + } + + @Override + public void close() throws IOException { + } + +} 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/sponge/SpongeSchematicV2Writer.java similarity index 51% rename from worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV2Writer.java index 38c0115e5..8504f0fe8 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/sponge/SpongeSchematicV2Writer.java @@ -17,62 +17,41 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.extent.clipboard.io; +package com.sk89q.worldedit.extent.clipboard.io.sponge; -import com.fastasyncworldedit.core.Fawe; -import com.google.common.collect.Maps; -import com.sk89q.jnbt.ByteArrayTag; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.IntArrayTag; -import com.sk89q.jnbt.IntTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.NBTOutputStream; -import com.sk89q.jnbt.ShortTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; +import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntMaps; +import org.enginehub.linbus.stream.LinBinaryIO; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinRootEntry; +import org.enginehub.linbus.tree.LinTagType; import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkNotNull; /** - * Writes schematic files using the Sponge schematic format. - * - * @deprecated Slow, resource intensive, but sometimes safer than using the recommended - * {@link com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriter}. - * Avoid using large clipboards to create schematics with this writer. + * Writes schematic files using the Sponge Schematic Specification (Version 2). */ -@Deprecated -public class SpongeSchematicWriter implements ClipboardWriter { +public class SpongeSchematicV2Writer implements ClipboardWriter { private static final int CURRENT_VERSION = 2; private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE; - private final NBTOutputStream outputStream; + private final DataOutputStream outputStream; - /** - * Create a new schematic writer. - * - * @param outputStream the output stream to write to - */ - public SpongeSchematicWriter(NBTOutputStream outputStream) { - checkNotNull(outputStream); + public SpongeSchematicV2Writer(DataOutputStream outputStream) { this.outputStream = outputStream; } @@ -82,17 +61,16 @@ public class SpongeSchematicWriter implements ClipboardWriter { // between upstream and FAWE clipboard.flush(); //FAWE end - // For now always write the latest version. Maybe provide support for earlier if more appear. - outputStream.writeNamedTag("Schematic", new CompoundTag(write2(clipboard))); + LinBinaryIO.write(outputStream, new LinRootEntry("Schematic", write2(clipboard))); } /** * Writes a version 2 schematic file. * * @param clipboard The clipboard - * @return The schematic map + * @return the schematic tag */ - private Map> write2(Clipboard clipboard) { + private LinCompoundTag write2(Clipboard clipboard) { Region region = clipboard.getRegion(); BlockVector3 origin = clipboard.getOrigin(); BlockVector3 min = region.getMinimumPoint(); @@ -111,34 +89,49 @@ public class SpongeSchematicWriter implements ClipboardWriter { throw new IllegalArgumentException("Length of region too large for a .schematic"); } - Map> schematic = new HashMap<>(); - schematic.put("Version", new IntTag(CURRENT_VERSION)); - schematic.put("DataVersion", new IntTag( - WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion())); + LinCompoundTag.Builder schematic = LinCompoundTag.builder(); + schematic.putInt("Version", CURRENT_VERSION); + schematic.putInt("DataVersion", + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion() + ); - Map> metadata = new HashMap<>(); - metadata.put("WEOffsetX", new IntTag(offset.x())); - metadata.put("WEOffsetY", new IntTag(offset.y())); - metadata.put("WEOffsetZ", new IntTag(offset.z())); - metadata.put("FAWEVersion", new IntTag(Fawe.instance().getVersion().build)); + LinCompoundTag.Builder metadata = LinCompoundTag.builder(); + metadata.putInt("WEOffsetX", offset.x()); + metadata.putInt("WEOffsetY", offset.y()); + metadata.putInt("WEOffsetZ", offset.z()); - schematic.put("Metadata", new CompoundTag(metadata)); + LinCompoundTag.Builder worldEditSection = LinCompoundTag.builder(); + worldEditSection.putString("Version", WorldEdit.getVersion()); + worldEditSection.putString("EditingPlatform", + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).id() + ); + worldEditSection.putIntArray("Offset", new int[]{offset.x(), offset.y(), offset.z()}); - schematic.put("Width", new ShortTag((short) width)); - schematic.put("Height", new ShortTag((short) height)); - schematic.put("Length", new ShortTag((short) length)); + LinCompoundTag.Builder platformsSection = LinCompoundTag.builder(); + for (Platform platform : WorldEdit.getInstance().getPlatformManager().getPlatforms()) { + platformsSection.put(platform.id(), LinCompoundTag + .builder() + .putString("Name", platform.getPlatformName()) + .putString("Version", platform.getPlatformVersion()) + .build()); + } + worldEditSection.put("Platforms", platformsSection.build()); + + metadata.put("WorldEdit", worldEditSection.build()); + + schematic.put("Metadata", metadata.build()); + + schematic.putShort("Width", (short) width); + schematic.putShort("Height", (short) height); + schematic.putShort("Length", (short) length); // The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin' - schematic.put("Offset", new IntArrayTag(new int[]{ - min.x(), - min.y(), - min.z(), - })); + schematic.putIntArray("Offset", new int[]{min.x(), min.y(), min.z(),}); int paletteMax = 0; - Map palette = new HashMap<>(); + Object2IntMap palette = new Object2IntLinkedOpenHashMap<>(); - List tileEntities = new ArrayList<>(); + LinListTag.Builder tileEntities = LinListTag.builder(LinTagType.compoundTag()); ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * height * length); @@ -150,8 +143,9 @@ public class SpongeSchematicWriter implements ClipboardWriter { int x0 = min.x() + x; BlockVector3 point = BlockVector3.at(x0, y0, z0); BaseBlock block = clipboard.getFullBlock(point); - if (block.getNbtData() != null) { - Map> values = new HashMap<>(block.getNbtData().getValue()); + LinCompoundTag nbt = block.getNbt(); + if (nbt != null) { + LinCompoundTag.Builder values = nbt.toBuilder(); values.remove("id"); // Remove 'id' if it exists. We want 'Id' @@ -160,16 +154,16 @@ public class SpongeSchematicWriter implements ClipboardWriter { values.remove("y"); values.remove("z"); - values.put("Id", new StringTag(block.getNbtId())); - values.put("Pos", new IntArrayTag(new int[]{x, y, z})); + values.putString("Id", block.getNbtId()); + values.putIntArray("Pos", new int[]{x, y, z}); - tileEntities.add(new CompoundTag(values)); + tileEntities.add(values.build()); } String blockKey = block.toImmutableState().getAsString(); int blockId; if (palette.containsKey(blockKey)) { - blockId = palette.get(blockKey); + blockId = palette.getInt(blockKey); } else { blockId = paletteMax; palette.put(blockKey, blockId); @@ -185,14 +179,14 @@ public class SpongeSchematicWriter implements ClipboardWriter { } } - schematic.put("PaletteMax", new IntTag(paletteMax)); + schematic.putInt("PaletteMax", paletteMax); - Map> paletteTag = new HashMap<>(); - palette.forEach((key, value) -> paletteTag.put(key, new IntTag(value))); + LinCompoundTag.Builder paletteTag = LinCompoundTag.builder(); + Object2IntMaps.fastForEach(palette, e -> paletteTag.putInt(e.getKey(), e.getIntValue())); - schematic.put("Palette", new CompoundTag(paletteTag)); - schematic.put("BlockData", new ByteArrayTag(buffer.toByteArray())); - schematic.put("BlockEntities", new ListTag(CompoundTag.class, tileEntities)); + schematic.put("Palette", paletteTag.build()); + schematic.putByteArray("BlockData", buffer.toByteArray()); + schematic.put("BlockEntities", tileEntities.build()); // version 2 stuff if (clipboard.hasBiomes()) { @@ -200,13 +194,16 @@ public class SpongeSchematicWriter implements ClipboardWriter { } if (!clipboard.getEntities().isEmpty()) { - writeEntities(clipboard, schematic); + LinListTag value = WriterUtil.encodeEntities(clipboard, false); + if (value != null) { + schematic.put("Entities", value); + } } - return schematic; + return schematic.build(); } - private void writeBiomes(Clipboard clipboard, Map> schematic) { + private void writeBiomes(Clipboard clipboard, LinCompoundTag.Builder schematic) { BlockVector3 min = clipboard.getMinimumPoint(); int width = clipboard.getRegion().getWidth(); int length = clipboard.getRegion().getLength(); @@ -214,7 +211,7 @@ public class SpongeSchematicWriter implements ClipboardWriter { ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * length); int paletteMax = 0; - Map palette = new HashMap<>(); + Object2IntMap palette = new Object2IntLinkedOpenHashMap<>(); for (int z = 0; z < length; z++) { int z0 = min.z() + z; @@ -226,7 +223,7 @@ public class SpongeSchematicWriter implements ClipboardWriter { String biomeKey = biome.id(); int biomeId; if (palette.containsKey(biomeKey)) { - biomeId = palette.get(biomeKey); + biomeId = palette.getInt(biomeKey); } else { biomeId = paletteMax; palette.put(biomeKey, biomeId); @@ -241,38 +238,13 @@ public class SpongeSchematicWriter implements ClipboardWriter { } } - schematic.put("BiomePaletteMax", new IntTag(paletteMax)); + schematic.putInt("BiomePaletteMax", paletteMax); - Map> paletteTag = new HashMap<>(); - palette.forEach((key, value) -> paletteTag.put(key, new IntTag(value))); + LinCompoundTag.Builder paletteTag = LinCompoundTag.builder(); + Object2IntMaps.fastForEach(palette, e -> paletteTag.putInt(e.getKey(), e.getIntValue())); - 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().id())); - 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)); + schematic.put("BiomePalette", paletteTag.build()); + schematic.putByteArray("BiomeData", buffer.toByteArray()); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Reader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Reader.java new file mode 100644 index 000000000..978cb8ba5 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Reader.java @@ -0,0 +1,168 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.sponge; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.internal.util.VarIntIterator; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockState; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.stream.LinStream; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinRootEntry; +import org.enginehub.linbus.tree.LinTagType; + +import java.io.IOException; +import java.util.Map; +import java.util.OptionalInt; + +/** + * Reads schematic files using the Sponge Schematic Specification. + */ +public class SpongeSchematicV3Reader implements ClipboardReader { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private final LinStream rootStream; + + public SpongeSchematicV3Reader(LinStream rootStream) { + this.rootStream = rootStream; + } + + @Override + public Clipboard read() throws IOException { + LinCompoundTag schematicTag = getBaseTag(); + ReaderUtil.checkSchematicVersion(3, schematicTag); + + final Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING); + int liveDataVersion = platform.getDataVersion(); + + VersionedDataFixer fixer = ReaderUtil.getVersionedDataFixer(schematicTag, platform, liveDataVersion); + return readVersion3(schematicTag, fixer); + } + + @Override + public OptionalInt getDataVersion() { + try { + LinCompoundTag schematicTag = getBaseTag(); + ReaderUtil.checkSchematicVersion(3, schematicTag); + + int dataVersion = schematicTag.getTag("DataVersion", LinTagType.intTag()).valueAsInt(); + if (dataVersion < 0) { + return OptionalInt.empty(); + } + return OptionalInt.of(dataVersion); + } catch (IOException e) { + return OptionalInt.empty(); + } + } + + private LinCompoundTag getBaseTag() throws IOException { + return LinRootEntry.readFrom(rootStream).value().getTag("Schematic", LinTagType.compoundTag()); + } + + private Clipboard readVersion3(LinCompoundTag schematicTag, VersionedDataFixer fixer) throws IOException { + int width = schematicTag.getTag("Width", LinTagType.shortTag()).valueAsShort() & 0xFFFF; + int height = schematicTag.getTag("Height", LinTagType.shortTag()).valueAsShort() & 0xFFFF; + int length = schematicTag.getTag("Length", LinTagType.shortTag()).valueAsShort() & 0xFFFF; + + BlockVector3 offset = ReaderUtil.decodeBlockVector3(schematicTag.findTag("Offset", LinTagType.intArrayTag())); + + BlockVector3 origin = BlockVector3.ZERO; + LinCompoundTag metadataTag = schematicTag.findTag("Metadata", LinTagType.compoundTag()); + if (metadataTag != null) { + LinCompoundTag worldeditMeta = metadataTag.findTag("WorldEdit", LinTagType.compoundTag()); + if (worldeditMeta != null) { + origin = ReaderUtil.decodeBlockVector3(worldeditMeta.findTag("Origin", LinTagType.intArrayTag())); + } + } + BlockVector3 min = offset.add(origin); + + BlockArrayClipboard clipboard = new BlockArrayClipboard(new CuboidRegion( + min, + min.add(width, height, length).subtract(BlockVector3.ONE) + )); + clipboard.setOrigin(origin); + + decodeBlocksIntoClipboard(fixer, schematicTag, clipboard); + + LinCompoundTag biomeContainer = schematicTag.findTag("Biomes", LinTagType.compoundTag()); + if (biomeContainer != null) { + readBiomes3(clipboard, biomeContainer, fixer); + } + + LinListTag entities = schematicTag.findListTag("Entities", LinTagType.compoundTag()); + if (entities != null) { + ReaderUtil.readEntities(clipboard, entities.value(), fixer, true); + } + + return clipboard; + } + + private void decodeBlocksIntoClipboard( + VersionedDataFixer fixer, LinCompoundTag schematic, BlockArrayClipboard clipboard + ) throws IOException { + LinCompoundTag blockContainer = schematic.getTag("Blocks", LinTagType.compoundTag()); + + LinCompoundTag paletteObject = blockContainer.getTag("Palette", LinTagType.compoundTag()); + Map palette = ReaderUtil.decodePalette(paletteObject, fixer); + + byte[] blocks = blockContainer.getTag("Data", LinTagType.byteArrayTag()).value(); + LinListTag blockEntities = blockContainer.getListTag("BlockEntities", LinTagType.compoundTag()); + + ReaderUtil.initializeClipboardFromBlocks(clipboard, palette, blocks, blockEntities, fixer, true); + } + + private void readBiomes3( + BlockArrayClipboard clipboard, LinCompoundTag biomeContainer, VersionedDataFixer fixer + ) throws IOException { + LinCompoundTag paletteTag = biomeContainer.getTag("Palette", LinTagType.compoundTag()); + + Int2ObjectMap palette = ReaderUtil.readBiomePalette(fixer, paletteTag, LOGGER); + + int width = clipboard.getRegion().getWidth(); + int length = clipboard.getRegion().getLength(); + + byte[] biomes = biomeContainer.getTag("Data", LinTagType.byteArrayTag()).value(); + BlockVector3 min = clipboard.getMinimumPoint(); + int index = 0; + for (VarIntIterator iter = new VarIntIterator(biomes); iter.hasNext(); index++) { + int nextBiomeId = iter.nextInt(); + BiomeType type = palette.get(nextBiomeId); + BlockVector3 pos = ReaderUtil.decodePositionFromDataIndex(width, length, index); + clipboard.setBiome(min.add(pos), type); + } + } + + @Override + public void close() throws IOException { + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Writer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Writer.java new file mode 100644 index 000000000..4030c2f90 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Writer.java @@ -0,0 +1,233 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.sponge; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.block.BaseBlock; +import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntMaps; +import org.enginehub.linbus.stream.LinBinaryIO; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinRootEntry; +import org.enginehub.linbus.tree.LinTagType; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.function.Function; + +/** + * Writes schematic files using the Sponge Schematic Specification (Version 3). + */ +public class SpongeSchematicV3Writer implements ClipboardWriter { + + private static final int CURRENT_VERSION = 3; + + private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE; + private final DataOutputStream outputStream; + + public SpongeSchematicV3Writer(DataOutputStream outputStream) { + this.outputStream = outputStream; + } + + @Override + public void write(Clipboard clipboard) throws IOException { + //FAWE start - ensure clipboard is flushed in case of using clipboard-on-disk. Maintains allowing of the same code + // between upstream and FAWE + clipboard.flush(); + //FAWE end + LinBinaryIO.write(outputStream, + new LinRootEntry("", LinCompoundTag.builder().put("Schematic", write3(clipboard)).build()) + ); + } + + /** + * Writes a version 3 schematic file. + * + * @param clipboard The clipboard + * @return The schematic map + */ + private LinCompoundTag write3(Clipboard clipboard) { + Region region = clipboard.getRegion(); + BlockVector3 origin = clipboard.getOrigin(); + BlockVector3 min = region.getMinimumPoint(); + BlockVector3 offset = min.subtract(origin); + int width = region.getWidth(); + int height = region.getHeight(); + int length = region.getLength(); + + if (width > MAX_SIZE) { + throw new IllegalArgumentException("Width of region too large for a .schematic"); + } + if (height > MAX_SIZE) { + throw new IllegalArgumentException("Height of region too large for a .schematic"); + } + if (length > MAX_SIZE) { + throw new IllegalArgumentException("Length of region too large for a .schematic"); + } + + LinCompoundTag.Builder schematic = LinCompoundTag.builder(); + schematic.putInt("Version", CURRENT_VERSION); + schematic.putInt("DataVersion", + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion() + ); + + LinCompoundTag.Builder metadata = LinCompoundTag.builder(); + metadata.putLong("Date", System.currentTimeMillis()); + + LinCompoundTag.Builder worldEditSection = LinCompoundTag.builder(); + worldEditSection.putString("Version", WorldEdit.getVersion()); + worldEditSection.putString("EditingPlatform", + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).id() + ); + worldEditSection.putIntArray("Origin", new int[]{origin.x(), origin.y(), origin.z()}); + + LinCompoundTag.Builder platformsSection = LinCompoundTag.builder(); + for (Platform platform : WorldEdit.getInstance().getPlatformManager().getPlatforms()) { + platformsSection.put(platform.id(), LinCompoundTag + .builder() + .putString("Name", platform.getPlatformName()) + .putString("Version", platform.getPlatformVersion()) + .build()); + } + worldEditSection.put("Platforms", platformsSection.build()); + + metadata.put("WorldEdit", worldEditSection.build()); + + schematic.put("Metadata", metadata.build()); + + schematic.putShort("Width", (short) width); + schematic.putShort("Height", (short) height); + schematic.putShort("Length", (short) length); + + schematic.putIntArray("Offset", new int[]{offset.x(), offset.y(), offset.z(),}); + + schematic.put("Blocks", encodeBlocks(clipboard)); + + if (clipboard.hasBiomes()) { + schematic.put("Biomes", encodeBiomes(clipboard)); + } + + if (!clipboard.getEntities().isEmpty()) { + LinListTag value = WriterUtil.encodeEntities(clipboard, true); + if (value != null) { + schematic.put("Entities", value); + } + } + + return schematic.build(); + } + + private static final class PaletteMap { + + private final Object2IntMap contents = new Object2IntLinkedOpenHashMap<>(); + private int nextId = 0; + + public int getId(String key) { + int result = contents.getOrDefault(key, -1); + if (result != -1) { + return result; + } + int newValue = nextId; + nextId++; + contents.put(key, newValue); + return newValue; + } + + public LinCompoundTag toNbt() { + LinCompoundTag.Builder result = LinCompoundTag.builder(); + Object2IntMaps.fastForEach(contents, e -> result.putInt(e.getKey(), e.getIntValue())); + return result.build(); + } + + } + + private LinCompoundTag encodeBlocks(Clipboard clipboard) { + LinListTag.Builder blockEntities = LinListTag.builder(LinTagType.compoundTag()); + LinCompoundTag.Builder result = encodePalettedData(clipboard, point -> { + BaseBlock block = clipboard.getFullBlock(point); + // Also compute block entity side-effect here + LinCompoundTag nbt = block.getNbt(); + if (nbt != null) { + LinCompoundTag.Builder builder = LinCompoundTag.builder(); + + builder.putString("Id", block.getNbtId()); + BlockVector3 adjustedPos = point.subtract(clipboard.getMinimumPoint()); + builder.putIntArray("Pos", new int[]{adjustedPos.x(), adjustedPos.y(), adjustedPos.z()}); + builder.put("Data", nbt); + + blockEntities.add(builder.build()); + } + return block.toImmutableState().getAsString(); + }); + + return result.put("BlockEntities", blockEntities.build()).build(); + } + + private LinCompoundTag encodeBiomes(Clipboard clipboard) { + return encodePalettedData(clipboard, point -> clipboard.getBiome(point).id()).build(); + } + + private LinCompoundTag.Builder encodePalettedData( + Clipboard clipboard, Function keyFunction + ) { + BlockVector3 min = clipboard.getMinimumPoint(); + int width = clipboard.getRegion().getWidth(); + int height = clipboard.getRegion().getHeight(); + int length = clipboard.getRegion().getLength(); + + PaletteMap paletteMap = new PaletteMap(); + + ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * height * length); + + for (int y = 0; y < height; y++) { + for (int z = 0; z < length; z++) { + for (int x = 0; x < width; x++) { + BlockVector3 point = min.add(x, y, z); + + String key = keyFunction.apply(point); + int id = paletteMap.getId(key); + + while ((id & -128) != 0) { + buffer.write(id & 127 | 128); + id >>>= 7; + } + buffer.write(id); + } + } + } + + return LinCompoundTag.builder().put("Palette", paletteMap.toNbt()).putByteArray("Data", buffer.toByteArray()); + } + + @Override + public void close() throws IOException { + outputStream.close(); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/VersionedDataFixer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/VersionedDataFixer.java new file mode 100644 index 000000000..35f6d58bc --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/VersionedDataFixer.java @@ -0,0 +1,47 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.sponge; + + +import com.sk89q.worldedit.world.DataFixer; + +import javax.annotation.Nullable; + +public final class VersionedDataFixer { //FAWE - public + private final int dataVersion; + @Nullable + private final DataFixer fixer; + + public VersionedDataFixer(int dataVersion, @Nullable DataFixer fixer) { //FAWE - public + this.dataVersion = dataVersion; + this.fixer = fixer; + } + + public boolean isActive() { + return fixer != null; + } + + public T fixUp(DataFixer.FixType type, T original) { + if (!isActive()) { + return original; + } + return fixer.fixUp(type, original, dataVersion); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/WriterUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/WriterUtil.java new file mode 100644 index 000000000..17ff5004d --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/WriterUtil.java @@ -0,0 +1,91 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.sponge; + +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.util.Location; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTagType; + +class WriterUtil { + + static LinListTag encodeEntities(Clipboard clipboard, boolean positionIsRelative) { + LinListTag.Builder entities = LinListTag.builder(LinTagType.compoundTag()); + for (Entity entity : clipboard.getEntities()) { + LinCompoundTag encoded = encodeEntity(clipboard, positionIsRelative, entity); + if (encoded != null) { + entities.add(encoded); + } + } + var result = entities.build(); + if (result.value().isEmpty()) { + return null; + } + return result; + } + + private static LinCompoundTag encodeEntity(Clipboard clipboard, boolean positionIsRelative, Entity e) { + BaseEntity state = e.getState(); + if (state == null) { + return null; + } + LinCompoundTag.Builder fullTagBuilder = LinCompoundTag.builder(); + LinCompoundTag.Builder dataTagBuilder = LinCompoundTag.builder(); + LinCompoundTag rawData = state.getNbt(); + if (rawData != null) { + dataTagBuilder.putAll(rawData.value()); + dataTagBuilder.remove("id"); + } + final Location location = e.getLocation(); + Vector3 pos = location.toVector(); + dataTagBuilder.put("Rotation", encodeRotation(location)); + if (positionIsRelative) { + pos = pos.subtract(clipboard.getMinimumPoint().toVector3()); + + fullTagBuilder.put("Data", dataTagBuilder.build()); + } else { + fullTagBuilder.putAll(dataTagBuilder.build().value()); + } + fullTagBuilder.putString("Id", state.getType().id()); + fullTagBuilder.put("Pos", encodeVector(pos)); + + return fullTagBuilder.build(); + } + + static LinListTag encodeVector(Vector3 vector) { + return LinListTag.builder(LinTagType.doubleTag()).add(LinDoubleTag.of(vector.x())).add(LinDoubleTag.of(vector.y())).add( + LinDoubleTag.of(vector.z())).build(); + } + + static LinListTag encodeRotation(Location location) { + return LinListTag + .builder(LinTagType.floatTag()) + .add(LinFloatTag.of(location.getYaw())) + .add(LinFloatTag.of(location.getPitch())) + .build(); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/package-info.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/package-info.java new file mode 100644 index 000000000..930ae5efb --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/package-info.java @@ -0,0 +1,26 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * This package is internal, containing implementation details of the Sponge Schematic + * Specification. Use the {@link com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats} or + * {@link com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat} classes to + * acquire readers and writers instead. + */ +package com.sk89q.worldedit.extent.clipboard.io.sponge; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/VarIntIterator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/VarIntIterator.java new file mode 100644 index 000000000..ac91c8365 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/VarIntIterator.java @@ -0,0 +1,81 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.internal.util; + +import it.unimi.dsi.fastutil.ints.IntIterator; + +import java.util.NoSuchElementException; +import java.util.PrimitiveIterator; + +/** + * Simple class to transform a {@code byte[]} into an iterator of the VarInts encoded in it. + */ +public class VarIntIterator implements PrimitiveIterator.OfInt { + + private final byte[] source; + private int index; + private boolean hasNextInt; + private int nextInt; + + public VarIntIterator(byte[] source) { + this.source = source; + } + + @Override + public boolean hasNext() { + if (hasNextInt) { + return true; + } + if (index >= source.length) { + return false; + } + + nextInt = readNextInt(); + return hasNextInt = true; + } + + private int readNextInt() { + int value = 0; + for (int bitsRead = 0; ; bitsRead += 7) { + if (index >= source.length) { + throw new IllegalStateException("Ran out of bytes while reading VarInt (probably corrupted data)"); + } + byte next = source[index]; + index++; + value |= (next & 0x7F) << bitsRead; + if (bitsRead > 7 * 5) { + throw new IllegalStateException("VarInt too big (probably corrupted data)"); + } + if ((next & 0x80) == 0) { + break; + } + } + return value; + } + + @Override + public int nextInt() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + hasNextInt = false; + return nextInt; + } +} From 528d2632fa6702cd8fe39946b403cdc33ac2c9bf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 Jul 2024 00:56:55 +0000 Subject: [PATCH 322/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.3.7 (#2833) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 48f436e07..79d9258b8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.3.4" +towny = "0.100.3.7" plotsquared = "7.3.8" # Third party From d4dd3638ffdd8b073557bbf1cfca5a59691c239f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 Jul 2024 01:00:58 +0000 Subject: [PATCH 323/466] Update dependency gradle to v8.9 (#2834) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4413138c..09523c0e5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From b2f36facd861d72f61ae9193e5fcf8b532d9519e Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Tue, 16 Jul 2024 14:50:41 +0100 Subject: [PATCH 324/466] fix: identify schematic format by file if not specified --- .../java/com/sk89q/worldedit/command/SchematicCommands.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 920a24901..8a7751bd4 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 @@ -356,7 +356,7 @@ public class SchematicCommands { File dir = Settings.settings().PATHS.PER_PLAYER_SCHEMATICS ? new File(saveDir, actor.getUniqueId().toString()) : saveDir; File file; if (filename.startsWith("#")) { - format = ClipboardFormats.findByAlias(formatName); + format = noExplicitFormat ? null : ClipboardFormats.findByAlias(formatName); String[] extensions; if (format != null) { extensions = format.getFileExtensions().toArray(new String[0]); @@ -396,7 +396,7 @@ public class SchematicCommands { .isInSubDirectory(saveDir, file)) + ")")); return; } - if (format == null) { + if (format == null || noExplicitFormat) { format = ClipboardFormats.findByFile(file); if (format == null) { actor.print(Caption.of("worldedit.schematic.unknown-format", TextComponent.of(formatName))); From bf07548695a05796f56a4118792af34561d3e103 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Wed, 17 Jul 2024 20:41:28 +0100 Subject: [PATCH 325/466] fix: add some file-extension bounds to schematic loading --- .../clipboard/io/BuiltInClipboardFormat.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java index 8a57411d6..736167056 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java @@ -112,6 +112,15 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { return false; } + @Override + public boolean isFormat(File file) { + String name = file.getName().toLowerCase(Locale.ROOT); + if (name.endsWith(".schematic") || name.endsWith(".mcedit") || name.endsWith(".mce")) { + return false; + } + return super.isFormat(file); + } + @Override public String getPrimaryFileExtension() { return "schem"; @@ -151,6 +160,15 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { return detectOldSpongeSchematic(inputStream, FastSchematicWriterV2.CURRENT_VERSION); } + @Override + public boolean isFormat(File file) { + String name = file.getName().toLowerCase(Locale.ROOT); + if (name.endsWith(".schematic") || name.endsWith(".mcedit") || name.endsWith(".mce")) { + return false; + } + return super.isFormat(file); + } + }, //FAWE end @@ -177,6 +195,15 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { //FAWE end } + @Override + public boolean isFormat(File file) { + String name = file.getName().toLowerCase(Locale.ROOT); + if (!name.endsWith(".schematic") && !name.endsWith(".mcedit") && !name.endsWith(".mce")) { + return false; + } + return super.isFormat(file); + } + @Override public boolean isFormat(InputStream inputStream) { LinRootEntry rootEntry; From 561ef4afdd3dd717d1f040b6440af39354d5826f Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Wed, 17 Jul 2024 20:45:20 +0100 Subject: [PATCH 326/466] chore: delegate to fast for checking if sponge schematic clipboard format --- .../extent/clipboard/io/BuiltInClipboardFormat.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java index 736167056..bfd6b2029 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java @@ -168,7 +168,6 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { } return super.isFormat(file); } - }, //FAWE end @@ -239,6 +238,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { public boolean isFormat(InputStream inputStream) { return detectOldSpongeSchematic(inputStream, 1); } + + @Override + public boolean isFormat(File file) { + return MCEDIT_SCHEMATIC.isFormat(file); + } }, /** @@ -268,6 +272,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { public boolean isFormat(InputStream inputStream) { return detectOldSpongeSchematic(inputStream, 2); } + + @Override + public boolean isFormat(File file) { + return FAST_V2.isFormat(file); + } }, SPONGE_V3_SCHEMATIC("sponge.3", "slow", "safe") { // FAWE - edit aliases for fast From 2e1a8f96652cc58e47b78a4a039bdbd786ac2243 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sun, 21 Jul 2024 09:19:59 +0200 Subject: [PATCH 327/466] Compile with target java 21, remove unsupported MC versions (#2836) * Compile with target java 21, remove unsupported MC versions * update bug report template --- .github/ISSUE_TEMPLATE/bug_report.yml | 7 +- buildSrc/src/main/kotlin/CommonJavaConfig.kt | 2 +- settings.gradle.kts | 2 +- .../adapters/adapter-1_19_4/build.gradle.kts | 17 - .../ext/fawe/v1_19_R3/PaperweightAdapter.java | 1077 ------- .../v1_19_R3/PaperweightDataConverters.java | 2799 ----------------- .../fawe/v1_19_R3/PaperweightFakePlayer.java | 93 - .../PaperweightWorldNativeAccess.java | 196 -- .../v1_19_R3/PaperweightBlockMaterial.java | 189 -- .../fawe/v1_19_R3/PaperweightFaweAdapter.java | 614 ---- .../PaperweightFaweWorldNativeAccess.java | 292 -- .../fawe/v1_19_R3/PaperweightGetBlocks.java | 1187 ------- .../v1_19_R3/PaperweightGetBlocks_Copy.java | 259 -- .../v1_19_R3/PaperweightMapChunkUtil.java | 34 - .../v1_19_R3/PaperweightPlatformAdapter.java | 748 ----- .../v1_19_R3/PaperweightPostProcessor.java | 175 -- .../PaperweightStarlightRelighter.java | 76 - .../PaperweightStarlightRelighterFactory.java | 25 - .../nbt/PaperweightLazyCompoundTag.java | 161 - .../fawe/v1_19_R3/regen/PaperweightRegen.java | 596 ---- .../adapters/adapter-1_20/build.gradle.kts | 17 - .../ext/fawe/v1_20_R1/PaperweightAdapter.java | 1131 ------- .../v1_20_R1/PaperweightDataConverters.java | 2798 ---------------- .../fawe/v1_20_R1/PaperweightFakePlayer.java | 93 - .../PaperweightWorldNativeAccess.java | 197 -- .../v1_20_R1/PaperweightBlockMaterial.java | 185 -- .../fawe/v1_20_R1/PaperweightFaweAdapter.java | 614 ---- .../PaperweightFaweWorldNativeAccess.java | 292 -- .../fawe/v1_20_R1/PaperweightGetBlocks.java | 1184 ------- .../v1_20_R1/PaperweightGetBlocks_Copy.java | 259 -- .../v1_20_R1/PaperweightMapChunkUtil.java | 34 - .../v1_20_R1/PaperweightPlatformAdapter.java | 764 ----- .../v1_20_R1/PaperweightPostProcessor.java | 175 -- .../PaperweightStarlightRelighter.java | 76 - .../PaperweightStarlightRelighterFactory.java | 25 - .../nbt/PaperweightLazyCompoundTag.java | 161 - .../fawe/v1_20_R1/regen/PaperweightRegen.java | 591 ---- 37 files changed, 6 insertions(+), 17139 deletions(-) delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_4/build.gradle.kts delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightDataConverters.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightFakePlayer.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightWorldNativeAccess.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightBlockMaterial.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweAdapter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweWorldNativeAccess.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightMapChunkUtil.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPostProcessor.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighterFactory.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/nbt/PaperweightLazyCompoundTag.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts delete mode 100644 worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightDataConverters.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightFakePlayer.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightWorldNativeAccess.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightBlockMaterial.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweAdapter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweWorldNativeAccess.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightMapChunkUtil.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPostProcessor.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighterFactory.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/nbt/PaperweightLazyCompoundTag.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 1de1aa8df..c223aae35 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -27,9 +27,10 @@ body: description: Which server version version you using? If your server version is not listed, it is not supported. Update to a supported version first. multiple: false options: - - '1.20.5/6' - - '1.20' - - '1.19.4' + - '1.21' + - '1.20.6' + - '1.20.4' + - '1.20.2' validations: required: true diff --git a/buildSrc/src/main/kotlin/CommonJavaConfig.kt b/buildSrc/src/main/kotlin/CommonJavaConfig.kt index 60860f7f7..d221a98d2 100644 --- a/buildSrc/src/main/kotlin/CommonJavaConfig.kt +++ b/buildSrc/src/main/kotlin/CommonJavaConfig.kt @@ -23,7 +23,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean val disabledLint = listOf( "processing", "path", "fallthrough", "serial", "overloads", "this-escape", ) - options.release.set(17) + options.release.set(21) options.compilerArgs.addAll(listOf("-Xlint:all") + disabledLint.map { "-Xlint:-$it" }) options.isDeprecation = true options.encoding = "UTF-8" diff --git a/settings.gradle.kts b/settings.gradle.kts index de52de2f9..4e1b292c5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,7 +2,7 @@ rootProject.name = "FastAsyncWorldEdit" include("worldedit-libs") -listOf("1_19_4", "1_20", "1_20_2", "1_20_4", "1_20_5", "1_21").forEach { +listOf("1_20_2", "1_20_4", "1_20_5", "1_21").forEach { include("worldedit-bukkit:adapters:adapter-$it") } diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_19_4/build.gradle.kts deleted file mode 100644 index e53d2497e..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/build.gradle.kts +++ /dev/null @@ -1,17 +0,0 @@ -import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension - -plugins { - java -} - -applyPaperweightAdapterConfiguration() - -repositories { - gradlePluginPortal() -} - -dependencies { - // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.19.4-R0.1-SNAPSHOT - the().paperDevBundle("1.19.4-R0.1-20230608.201059-104") - compileOnly(libs.paperlib) -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java deleted file mode 100644 index 87135fa86..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java +++ /dev/null @@ -1,1077 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R3; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Sets; -import com.google.common.util.concurrent.Futures; -import com.mojang.datafixers.util.Either; -import com.mojang.serialization.Lifecycle; -import com.sk89q.jnbt.NBTConstants; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.blocks.BaseItem; -import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.PaperweightPlatformAdapter; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.extension.platform.Watchdog; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.Constants; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; -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.util.SideEffect; -import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; -import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.world.DataFixer; -import com.sk89q.worldedit.world.RegenOptions; -import com.sk89q.worldedit.world.biome.BiomeCategory; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.BiomeTypes; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.item.ItemType; -import net.minecraft.Util; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.HolderSet; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; -import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.progress.ChunkProgressListener; -import net.minecraft.util.StringRepresentable; -import net.minecraft.util.thread.BlockableEventLoop; -import net.minecraft.world.Clearable; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelSettings; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.StructureBlockEntity; -import net.minecraft.world.level.block.state.StateDefinition; -import net.minecraft.world.level.block.state.properties.DirectionProperty; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.WorldOptions; -import net.minecraft.world.level.storage.LevelStorageSource; -import net.minecraft.world.level.storage.PrimaryLevelData; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World.Environment; -import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_19_R3.CraftServer; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; -import org.bukkit.generator.ChunkGenerator; -import org.enginehub.linbus.common.LinTagId; -import org.enginehub.linbus.tree.LinByteArrayTag; -import org.enginehub.linbus.tree.LinByteTag; -import org.enginehub.linbus.tree.LinCompoundTag; -import org.enginehub.linbus.tree.LinDoubleTag; -import org.enginehub.linbus.tree.LinEndTag; -import org.enginehub.linbus.tree.LinFloatTag; -import org.enginehub.linbus.tree.LinIntArrayTag; -import org.enginehub.linbus.tree.LinIntTag; -import org.enginehub.linbus.tree.LinListTag; -import org.enginehub.linbus.tree.LinLongArrayTag; -import org.enginehub.linbus.tree.LinLongTag; -import org.enginehub.linbus.tree.LinShortTag; -import org.enginehub.linbus.tree.LinStringTag; -import org.enginehub.linbus.tree.LinTag; -import org.enginehub.linbus.tree.LinTagType; -import org.spigotmc.SpigotConfig; -import org.spigotmc.WatchdogThread; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.OptionalInt; -import java.util.OptionalLong; -import java.util.Set; -import java.util.TreeMap; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -public final class PaperweightAdapter implements BukkitImplAdapter { - - private final Logger logger = Logger.getLogger(getClass().getCanonicalName()); - - private final Field serverWorldsField; - private final Method getChunkFutureMethod; - private final Field chunkProviderExecutorField; - private final Watchdog watchdog; - - // ------------------------------------------------------------------------ - // Code that may break between versions of Minecraft - // ------------------------------------------------------------------------ - - public PaperweightAdapter() throws NoSuchFieldException, NoSuchMethodException { - // A simple test - CraftServer.class.cast(Bukkit.getServer()); - - int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); - if (dataVersion != 3337) { - throw new UnsupportedClassVersionError("Not 1.19.4!"); - } - - serverWorldsField = CraftServer.class.getDeclaredField("worlds"); - serverWorldsField.setAccessible(true); - - getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod( - Refraction.pickName("getChunkFutureMainThread", "c"), - int.class, int.class, ChunkStatus.class, boolean.class - ); - getChunkFutureMethod.setAccessible(true); - - chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField( - Refraction.pickName("mainThreadProcessor", "g") - ); - chunkProviderExecutorField.setAccessible(true); - - new PaperweightDataConverters(CraftMagicNumbers.INSTANCE.getDataVersion(), this).buildUnoptimized(); - - Watchdog watchdog; - try { - Class.forName("org.spigotmc.WatchdogThread"); - watchdog = new SpigotWatchdog(); - } catch (ClassNotFoundException | NoSuchFieldException e) { - try { - watchdog = new MojangWatchdog(((CraftServer) Bukkit.getServer()).getServer()); - } catch (NoSuchFieldException ex) { - watchdog = null; - } - } - this.watchdog = watchdog; - - try { - Class.forName("org.spigotmc.SpigotConfig"); - SpigotConfig.config.set("world-settings.faweregentempworld.verbose", false); - } catch (ClassNotFoundException ignored) { - } - } - - @Override - public DataFixer getDataFixer() { - return PaperweightDataConverters.INSTANCE; - } - - /** - * Read the given NBT data into the given tile entity. - * - * @param tileEntity the tile entity - * @param tag the tag - */ - static void readTagIntoTileEntity(net.minecraft.nbt.CompoundTag tag, BlockEntity tileEntity) { - tileEntity.load(tag); - tileEntity.setChanged(); - } - - /** - * Get the ID string of the given entity. - * - * @param entity the entity - * @return the entity ID - */ - private static String getEntityId(Entity entity) { - return EntityType.getKey(entity.getType()).toString(); - } - - /** - * Create an entity using the given entity ID. - * - * @param id the entity ID - * @param world the world - * @return an entity or null - */ - @Nullable - private static Entity createEntityFromId(String id, net.minecraft.world.level.Level world) { - return EntityType.byString(id).map(t -> t.create(world)).orElse(null); - } - - /** - * Write the given NBT data into the given entity. - * - * @param entity the entity - * @param tag the tag - */ - private static void readTagIntoEntity(net.minecraft.nbt.CompoundTag tag, Entity entity) { - entity.load(tag); - } - - /** - * Write the entity's NBT data to the given tag. - * - * @param entity the entity - * @param tag the tag - */ - private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag tag) { - //FAWE start - avoid villager async catcher - PaperweightPlatformAdapter.readEntityIntoTag(entity, tag); - //FAWE end - } - - private static Block getBlockFromType(BlockType blockType) { - - return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK).get(ResourceLocation.tryParse(blockType.id())); - } - - private static Item getItemFromType(ItemType itemType) { - return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(itemType.id())); - } - - public BiomeType adapt(Biome biome) { - var mcBiome = ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getKey(biome); - if (mcBiome == null) { - return null; - } - return BiomeType.REGISTRY.get(mcBiome.toString()); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockData data) { - net.minecraft.world.level.block.state.BlockState state = ((CraftBlockData) data).getState(); - int combinedId = Block.getId(state); - return combinedId == 0 && state.getBlock() != Blocks.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockState state) { - Block mcBlock = getBlockFromType(state.getBlockType()); - net.minecraft.world.level.block.state.BlockState newState = mcBlock.defaultBlockState(); - Map, Object> states = state.getStates(); - newState = applyProperties(mcBlock.getStateDefinition(), newState, states); - final int combinedId = Block.getId(newState); - return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); - } - - @Override - public BlockState getBlock(Location location) { - checkNotNull(location); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - int internalId = Block.getId(blockData); - BlockState state = BlockStateIdAccess.getBlockStateById(internalId); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - - return state; - } - - @Override - public BaseBlock getFullBlock(Location location) { - BlockState state = getBlock(location); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - - // Read the NBT data - BlockEntity te = chunk.getBlockEntity(blockPos); - if (te != null) { - net.minecraft.nbt.CompoundTag tag = te.saveWithId(); - return state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); - } - - return state.toBaseBlock(); - } - - @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightWorldNativeAccess(this, - new WeakReference<>(((CraftWorld) world).getHandle())); - } - - private static net.minecraft.core.Direction adapt(Direction face) { - switch (face) { - case NORTH: - return net.minecraft.core.Direction.NORTH; - case SOUTH: - return net.minecraft.core.Direction.SOUTH; - case WEST: - return net.minecraft.core.Direction.WEST; - case EAST: - return net.minecraft.core.Direction.EAST; - case DOWN: - return net.minecraft.core.Direction.DOWN; - case UP: - default: - return net.minecraft.core.Direction.UP; - } - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - private net.minecraft.world.level.block.state.BlockState applyProperties( - StateDefinition stateContainer, - net.minecraft.world.level.block.state.BlockState newState, - Map, Object> states - ) { - for (Map.Entry, Object> state : states.entrySet()) { - net.minecraft.world.level.block.state.properties.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.world.level.block.state.properties.EnumProperty) { - String enumName = (String) value; - value = ((net.minecraft.world.level.block.state.properties.EnumProperty) property) - .getValue(enumName).orElseThrow(() -> - new IllegalStateException( - "Enum property " + property.getName() + " does not contain " + enumName - ) - ); - } - - newState = newState.setValue( - (net.minecraft.world.level.block.state.properties.Property) property, - (Comparable) value - ); - } - return newState; - } - - @Override - public BaseEntity getEntity(org.bukkit.entity.Entity entity) { - checkNotNull(entity); - - CraftEntity craftEntity = ((CraftEntity) entity); - Entity mcEntity = craftEntity.getHandle(); - - // Do not allow creating of passenger entity snapshots, passengers are included in the vehicle entity - if (mcEntity.isPassenger()) { - return null; - } - - String id = getEntityId(mcEntity); - - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - readEntityIntoTag(mcEntity, tag); - return new BaseEntity( - com.sk89q.worldedit.world.entity.EntityTypes.get(id), - LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) - ); - } - - @Nullable - @Override - public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state) { - checkNotNull(location); - checkNotNull(state); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - ServerLevel worldServer = craftWorld.getHandle(); - - Entity createdEntity = createEntityFromId(state.getType().id(), craftWorld.getHandle()); - - if (createdEntity != null) { - LinCompoundTag nativeTag = state.getNbt(); - if (nativeTag != null) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeLin(nativeTag); - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - readTagIntoEntity(tag, createdEntity); - } - - createdEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - - worldServer.addFreshEntity(createdEntity, SpawnReason.CUSTOM); - return createdEntity.getBukkitEntity(); - } else { - return null; - } - } - - // This removes all unwanted tags from the main entity and all its passengers - private void removeUnwantedEntityTagsRecursively(net.minecraft.nbt.CompoundTag tag) { - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - - // Adapted from net.minecraft.world.entity.EntityType#loadEntityRecursive - if (tag.contains("Passengers", NBTConstants.TYPE_LIST)) { - net.minecraft.nbt.ListTag nbttaglist = tag.getList("Passengers", NBTConstants.TYPE_COMPOUND); - - for (int i = 0; i < nbttaglist.size(); ++i) { - removeUnwantedEntityTagsRecursively(nbttaglist.getCompound(i)); - } - } - } - - @Override - public Component getRichBlockName(BlockType blockType) { - return TranslatableComponent.of(getBlockFromType(blockType).getDescriptionId()); - } - - @Override - public Component getRichItemName(ItemType itemType) { - return TranslatableComponent.of(getItemFromType(itemType).getDescriptionId()); - } - - @Override - public Component getRichItemName(BaseItemStack itemStack) { - return TranslatableComponent.of(CraftItemStack.asNMSCopy(BukkitAdapter.adapt(itemStack)).getDescriptionId()); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - private static final LoadingCache> PROPERTY_CACHE = CacheBuilder - .newBuilder() - .build(new CacheLoader<>() { - @Override - public Property load(net.minecraft.world.level.block.state.properties.Property state) { - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else if (state instanceof DirectionProperty) { - return new DirectionalProperty( - state.getName(), - new ArrayList<>((List) state - .getPossibleValues() - .stream() - .map(e -> Direction.valueOf(((StringRepresentable) e) - .getSerializedName() - .toUpperCase(Locale.ROOT))) - .toList()) - ); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - return new EnumProperty( - state.getName(), - new ArrayList<>((List) state - .getPossibleValues() - .stream() - .map(e -> ((StringRepresentable) e).getSerializedName()) - .toList()) - ); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else { - throw new IllegalArgumentException("WorldEdit needs an update to support " + state - .getClass() - .getSimpleName()); - } - } - }); - - @SuppressWarnings({ "rawtypes" }) - @Override - public Map> getProperties(BlockType blockType) { - Map> properties = new TreeMap<>(); - Block block = getBlockFromType(blockType); - StateDefinition blockStateList = - block.getStateDefinition(); - for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { - Property property = PROPERTY_CACHE.getUnchecked(state); - properties.put(property.getName(), property); - } - return properties; - } - - @Override - public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) { - ((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create( - new StructureBlockEntity( - new BlockPos(pos.x(), pos.y(), pos.z()), - Blocks.STRUCTURE_BLOCK.defaultBlockState() - ), - __ -> (net.minecraft.nbt.CompoundTag) fromNativeLin(nbtData) - )); - } - - @Override - public void sendFakeOP(Player player) { - ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( - ((CraftPlayer) player).getHandle(), (byte) 28 - )); - } - - @Override - public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { - ItemStack stack = new ItemStack( - DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().id())), - item.getAmount() - ); - stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData()))); - return CraftItemStack.asCraftMirror(stack); - } - - @Override - public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { - final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); - final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); - weStack.setNbt(((LinCompoundTag) toNativeLin(nmsStack.getTag()))); - return weStack; - } - - private final LoadingCache fakePlayers - = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); - - @Override - public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) { - CraftWorld craftWorld = (CraftWorld) world; - ServerLevel worldServer = craftWorld.getHandle(); - ItemStack stack = CraftItemStack.asNMSCopy(BukkitAdapter.adapt(item instanceof BaseItemStack - ? ((BaseItemStack) item) : new BaseItemStack(item.getType(), item.getNbtData(), 1))); - stack.setTag((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData())); - - PaperweightFakePlayer fakePlayer; - try { - fakePlayer = fakePlayers.get(worldServer); - } catch (ExecutionException ignored) { - return false; - } - fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); - fakePlayer.absMoveTo(position.x(), position.y(), position.z(), - (float) face.toVector().toYaw(), (float) face.toVector().toPitch()); - - final BlockPos blockPos = new BlockPos(position.x(), position.y(), position.z()); - final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos); - final net.minecraft.core.Direction enumFacing = adapt(face); - BlockHitResult rayTrace = new BlockHitResult(blockVec, enumFacing, blockPos, false); - UseOnContext context = new UseOnContext(fakePlayer, InteractionHand.MAIN_HAND, rayTrace); - InteractionResult result = stack.useOn(context, InteractionHand.MAIN_HAND); - if (result != InteractionResult.SUCCESS) { - if (worldServer.getBlockState(blockPos).use(worldServer, fakePlayer, InteractionHand.MAIN_HAND, rayTrace).consumesAction()) { - result = InteractionResult.SUCCESS; - } else { - result = stack.getItem().use(worldServer, fakePlayer, InteractionHand.MAIN_HAND).getResult(); - } - } - - return result == InteractionResult.SUCCESS; - } - - @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 position, BlockState blockState) { - int internalId = BlockStateIdAccess.getBlockStateId(blockState); - net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId); - return blockData.canSurvive(((CraftWorld) world).getHandle(), new BlockPos(position.x(), position.y(), position.z())); - } - - @Override - public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) { - try { - doRegen(bukkitWorld, region, extent, options); - } catch (Exception e) { - throw new IllegalStateException("Regen failed.", e); - } - - return true; - } - - private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { - Environment env = bukkitWorld.getEnvironment(); - ChunkGenerator gen = bukkitWorld.getGenerator(); - - Path tempDir = Files.createTempDirectory("WorldEditWorldGen"); - LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir); - ResourceKey worldDimKey = getWorldDimKey(env); - try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { - ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); - PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() - .getWorldData().overworldData(); - WorldOptions originalOpts = levelProperties.worldGenOptions(); - - long seed = options.getSeed().orElse(originalWorld.getSeed()); - WorldOptions newOpts = options.getSeed().isPresent() - ? originalOpts.withSeed(OptionalLong.of(seed)) - : originalOpts; - - LevelSettings newWorldSettings = new LevelSettings( - "faweregentempworld", - levelProperties.settings.gameType(), - levelProperties.settings.hardcore(), - levelProperties.settings.difficulty(), - levelProperties.settings.allowCommands(), - levelProperties.settings.gameRules(), - levelProperties.settings.getDataConfiguration() - ); - - PrimaryLevelData.SpecialWorldProperty specialWorldProperty = - levelProperties.isFlatWorld() - ? PrimaryLevelData.SpecialWorldProperty.FLAT - : levelProperties.isDebugWorld() - ? PrimaryLevelData.SpecialWorldProperty.DEBUG - : PrimaryLevelData.SpecialWorldProperty.NONE; - - PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable()); - - ServerLevel freshWorld = new ServerLevel( - originalWorld.getServer(), - originalWorld.getServer().executor, - session, newWorldData, - originalWorld.dimension(), - new LevelStem( - originalWorld.dimensionTypeRegistration(), - originalWorld.getChunkSource().getGenerator() - ), - new NoOpWorldLoadListener(), - originalWorld.isDebug(), - seed, - ImmutableList.of(), - false, - env, - gen, - bukkitWorld.getBiomeProvider() - ); - try { - regenForWorld(region, extent, freshWorld, options); - } finally { - freshWorld.getChunkSource().close(false); - } - } finally { - try { - @SuppressWarnings("unchecked") - Map map = (Map) serverWorldsField.get(Bukkit.getServer()); - map.remove("faweregentempworld"); - } catch (IllegalAccessException ignored) { - } - SafeFiles.tryHardToDeleteDir(tempDir); - } - } - - private BiomeType adapt(ServerLevel serverWorld, Biome origBiome) { - ResourceLocation key = serverWorld.registryAccess().registryOrThrow(Registries.BIOME).getKey(origBiome); - if (key == null) { - return null; - } - return BiomeTypes.get(key.toString()); - } - - @SuppressWarnings("unchecked") - private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld, RegenOptions options) throws WorldEditException { - List> chunkLoadings = submitChunkLoadTasks(region, serverWorld); - BlockableEventLoop executor; - try { - executor = (BlockableEventLoop) chunkProviderExecutorField.get(serverWorld.getChunkSource()); - } catch (IllegalAccessException e) { - throw new IllegalStateException("Couldn't get executor for chunk loading.", e); - } - executor.managedBlock(() -> { - // bail out early if a future fails - if (chunkLoadings.stream().anyMatch(ftr -> - ftr.isDone() && Futures.getUnchecked(ftr) == null - )) { - return false; - } - return chunkLoadings.stream().allMatch(CompletableFuture::isDone); - }); - Map chunks = new HashMap<>(); - for (CompletableFuture future : chunkLoadings) { - @Nullable - ChunkAccess chunk = future.getNow(null); - checkState(chunk != null, "Failed to generate a chunk, regen failed."); - chunks.put(chunk.getPos(), chunk); - } - - for (BlockVector3 vec : region) { - BlockPos pos = new BlockPos(vec.x(), vec.y(), vec.z()); - ChunkAccess chunk = chunks.get(new ChunkPos(pos)); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(pos); - int internalId = Block.getId(blockData); - BlockStateHolder state = BlockStateIdAccess.getBlockStateById(internalId); - Objects.requireNonNull(state); - BlockEntity blockEntity = chunk.getBlockEntity(pos); - if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); - state = state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); - } - extent.setBlock(vec, state.toBaseBlock()); - if (options.shouldRegenBiomes()) { - Biome origBiome = chunk.getNoiseBiome(vec.x(), vec.y(), vec.z()).value(); - BiomeType adaptedBiome = adapt(serverWorld, origBiome); - if (adaptedBiome != null) { - extent.setBiome(vec, adaptedBiome); - } - } - } - } - - @SuppressWarnings("unchecked") - private List> submitChunkLoadTasks(Region region, ServerLevel serverWorld) { - ServerChunkCache chunkManager = serverWorld.getChunkSource(); - List> chunkLoadings = new ArrayList<>(); - // Pre-gen all the chunks - for (BlockVector2 chunk : region.getChunks()) { - try { - //noinspection unchecked - chunkLoadings.add( - ((CompletableFuture>) - getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) - .thenApply(either -> either.left().orElse(null)) - ); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalStateException("Couldn't load chunk for regen.", e); - } - } - return chunkLoadings; - } - - private ResourceKey getWorldDimKey(Environment env) { - switch (env) { - case NETHER: - return LevelStem.NETHER; - case THE_END: - return LevelStem.END; - case NORMAL: - default: - return LevelStem.OVERWORLD; - } - } - - private static final Set SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( - SideEffect.NEIGHBORS, - SideEffect.LIGHTING, - SideEffect.VALIDATION, - SideEffect.ENTITY_AI, - SideEffect.EVENTS, - SideEffect.UPDATE - ); - - @Override - public Set getSupportedSideEffects() { - return SUPPORTED_SIDE_EFFECTS; - } - - @Override - public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) { - ServerLevel originalWorld = ((CraftWorld) world).getHandle(); - - BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z())); - if (entity instanceof Clearable) { - ((Clearable) entity).clearContent(); - return true; - } - return false; - } - - @Override - public void initializeRegistries() { - DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer(); - // Biomes - for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.BIOME).keySet()) { - if (BiomeType.REGISTRY.get(name.toString()) == null) { - BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString())); - } - } - - // BiomeCategories - Registry biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); - biomeRegistry.getTagNames().forEach(tagKey -> { - String key = tagKey.location().toString(); - if (BiomeCategory.REGISTRY.get(key) == null) { - BiomeCategory.REGISTRY.register(key, new BiomeCategory( - key, - () -> biomeRegistry.getTag(tagKey) - .stream() - .flatMap(HolderSet.Named::stream) - .map(Holder::value) - .map(this::adapt) - .collect(Collectors.toSet())) - ); - } - }); - } - - // ------------------------------------------------------------------------ - // Code that is less likely to break - // ------------------------------------------------------------------------ - - /** - * Converts from a non-native NMS NBT structure to a native WorldEdit NBT - * structure. - * - * @param foreign non-native NMS NBT structure - * @return native WorldEdit NBT structure - */ - @Override - public LinTag toNativeLin(net.minecraft.nbt.Tag foreign) { - if (foreign == null) { - return null; - } - if (foreign instanceof net.minecraft.nbt.CompoundTag) { - Map> values = new HashMap<>(); - Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); - - for (String str : foreignKeys) { - net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); - values.put(str, toNativeLin(base)); - } - return LinCompoundTag.of(values); - } else if (foreign instanceof net.minecraft.nbt.ByteTag) { - return LinByteTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); - } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { - return LinByteArrayTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); - } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { - return LinDoubleTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); - } else if (foreign instanceof net.minecraft.nbt.FloatTag) { - return LinFloatTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); - } else if (foreign instanceof net.minecraft.nbt.IntTag) { - return LinIntTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); - } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { - return LinIntArrayTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); - } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { - return LinLongArrayTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); - } else if (foreign instanceof net.minecraft.nbt.ListTag) { - try { - return toNativeLinList((net.minecraft.nbt.ListTag) foreign); - } catch (Throwable e) { - logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); - } - } else if (foreign instanceof net.minecraft.nbt.LongTag) { - return LinLongTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); - } else if (foreign instanceof net.minecraft.nbt.ShortTag) { - return LinShortTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); - } else if (foreign instanceof net.minecraft.nbt.StringTag) { - return LinStringTag.of(foreign.getAsString()); - } else if (foreign instanceof net.minecraft.nbt.EndTag) { - return LinEndTag.instance(); - } - throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); - } - - /** - * Convert a foreign NBT list tag into a native WorldEdit one. - * - * @param foreign the foreign tag - * @return the converted tag - * @throws SecurityException on error - * @throws IllegalArgumentException on error - */ - private LinListTag toNativeLinList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { - LinListTag.Builder> builder = LinListTag.builder( - LinTagType.fromId(LinTagId.fromId(foreign.getElementType())) - ); - - for (net.minecraft.nbt.Tag tag : foreign) { - builder.add(toNativeLin(tag)); - } - - return builder.build(); - } - - /** - * Converts a WorldEdit-native NBT structure to a NMS structure. - * - * @param foreign structure to convert - * @return non-native structure - */ - @Override - public net.minecraft.nbt.Tag fromNativeLin(LinTag foreign) { - if (foreign == null) { - return null; - } - if (foreign instanceof LinCompoundTag compoundTag) { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - for (var entry : compoundTag.value().entrySet()) { - tag.put(entry.getKey(), fromNativeLin(entry.getValue())); - } - return tag; - } else if (foreign instanceof LinByteTag byteTag) { - return net.minecraft.nbt.ByteTag.valueOf(byteTag.valueAsByte()); - } else if (foreign instanceof LinByteArrayTag byteArrayTag) { - return new net.minecraft.nbt.ByteArrayTag(byteArrayTag.value()); - } else if (foreign instanceof LinDoubleTag doubleTag) { - return net.minecraft.nbt.DoubleTag.valueOf(doubleTag.valueAsDouble()); - } else if (foreign instanceof LinFloatTag floatTag) { - return net.minecraft.nbt.FloatTag.valueOf(floatTag.valueAsFloat()); - } else if (foreign instanceof LinIntTag intTag) { - return net.minecraft.nbt.IntTag.valueOf(intTag.valueAsInt()); - } else if (foreign instanceof LinIntArrayTag intArrayTag) { - return new net.minecraft.nbt.IntArrayTag(intArrayTag.value()); - } else if (foreign instanceof LinLongArrayTag longArrayTag) { - return new net.minecraft.nbt.LongArrayTag(longArrayTag.value()); - } else if (foreign instanceof LinListTag listTag) { - net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); - for (var t : listTag.value()) { - tag.add(fromNativeLin(t)); - } - return tag; - } else if (foreign instanceof LinLongTag longTag) { - return net.minecraft.nbt.LongTag.valueOf(longTag.valueAsLong()); - } else if (foreign instanceof LinShortTag shortTag) { - return net.minecraft.nbt.ShortTag.valueOf(shortTag.valueAsShort()); - } else if (foreign instanceof LinStringTag stringTag) { - return net.minecraft.nbt.StringTag.valueOf(stringTag.value()); - } else if (foreign instanceof LinEndTag) { - return net.minecraft.nbt.EndTag.INSTANCE; - } else { - throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); - } - } - - @Override - public boolean supportsWatchdog() { - return watchdog != null; - } - - @Override - public void tickWatchdog() { - watchdog.tick(); - } - - private class SpigotWatchdog implements Watchdog { - private final Field instanceField; - private final Field lastTickField; - - SpigotWatchdog() throws NoSuchFieldException { - Field instanceField = WatchdogThread.class.getDeclaredField("instance"); - instanceField.setAccessible(true); - this.instanceField = instanceField; - - Field lastTickField = WatchdogThread.class.getDeclaredField("lastTick"); - lastTickField.setAccessible(true); - this.lastTickField = lastTickField; - } - - @Override - public void tick() { - try { - WatchdogThread instance = (WatchdogThread) this.instanceField.get(null); - if ((long) lastTickField.get(instance) != 0) { - WatchdogThread.tick(); - } - } catch (IllegalAccessException e) { - logger.log(Level.WARNING, "Failed to tick watchdog", e); - } - } - } - - private static class MojangWatchdog implements Watchdog { - private final DedicatedServer server; - private final Field tickField; - - MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { - this.server = server; - Field tickField = MinecraftServer.class.getDeclaredField( - Refraction.pickName("nextTickTime", "ah") - ); - if (tickField.getType() != long.class) { - throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); - } - tickField.setAccessible(true); - this.tickField = tickField; - } - - @Override - public void tick() { - try { - tickField.set(server, Util.getMillis()); - } catch (IllegalAccessException ignored) { - } - } - } - - private static class NoOpWorldLoadListener implements ChunkProgressListener { - @Override - public void updateSpawnPos(ChunkPos spawnPos) { - } - - @Override - public void onStatusChange(ChunkPos pos, @org.jetbrains.annotations.Nullable ChunkStatus status) { - } - - @Override - public void start() { - } - - @Override - public void stop() { - } - - @Override - public void setChunkRadius(int radius) { - } - } -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightDataConverters.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightDataConverters.java deleted file mode 100644 index 50de3467e..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightDataConverters.java +++ /dev/null @@ -1,2799 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R3; - -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; -import com.mojang.datafixers.DSL.TypeReference; -import com.mojang.datafixers.DataFixer; -import com.mojang.datafixers.DataFixerBuilder; -import com.mojang.datafixers.schemas.Schema; -import com.mojang.serialization.Dynamic; -import net.minecraft.core.Direction; -import net.minecraft.nbt.NbtOps; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.GsonHelper; -import net.minecraft.util.StringUtil; -import net.minecraft.util.datafix.DataFixers; -import net.minecraft.util.datafix.fixes.References; -import net.minecraft.world.item.DyeColor; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.enginehub.linbus.tree.LinCompoundTag; - -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({ "rawtypes", "unchecked" }) -class PaperweightDataConverters 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((LinCompoundTag) original, srcVer); - } else if (type == FixTypes.BLOCK_ENTITY) { - return (T) fixBlockEntity((LinCompoundTag) original, srcVer); - } else if (type == FixTypes.ENTITY) { - return (T) fixEntity((LinCompoundTag) 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 LinCompoundTag fixChunk(LinCompoundTag originalChunk, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(originalChunk); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); - return (LinCompoundTag) adapter.toNativeLin(fixed); - } - - private LinCompoundTag fixBlockEntity(LinCompoundTag origTileEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origTileEnt); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); - return (LinCompoundTag) adapter.toNativeLin(fixed); - } - - private LinCompoundTag fixEntity(LinCompoundTag origEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origEnt); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); - return (LinCompoundTag) adapter.toNativeLin(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(References.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.contains("Properties", 10)) { - sb.append('['); - net.minecraft.nbt.CompoundTag props = tagCompound.getCompound("Properties"); - sb.append(props.getAllKeys().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, References.BIOME); - } - - private String fixItemType(String key, int srcVer) { - return fixName(key, srcVer, References.ITEM_NAME); - } - - private static String fixName(String key, int srcVer, TypeReference type) { - return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, net.minecraft.nbt.StringTag.valueOf(key)), srcVer, DATA_VERSION) - .getValue().getAsString(); - } - - private final PaperweightAdapter adapter; - - private static final NbtOps OPS_NBT = NbtOps.INSTANCE; - private static final int LEGACY_VERSION = 1343; - private static int DATA_VERSION; - static PaperweightDataConverters 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(References.LEVEL), - PLAYER(References.PLAYER), - CHUNK(References.CHUNK), - BLOCK_ENTITY(References.BLOCK_ENTITY), - ENTITY(References.ENTITY), - ITEM_INSTANCE(References.ITEM_STACK), - OPTIONS(References.OPTIONS), - STRUCTURE(References.STRUCTURE); - - private final TypeReference type; - - LegacyType(TypeReference type) { - this.type = type; - DFU_TO_LEGACY.put(type.typeName(), this); - } - - public TypeReference getDFUType() { - return type; - } - } - - PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { - super(dataVersion); - DATA_VERSION = dataVersion; - INSTANCE = this; - this.adapter = adapter; - registerConverters(); - registerInspectors(); - } - - - // Called after fixers are built and ready for FIXING - @Override - public DataFixer buildUnoptimized() { - return this.fixer = new WrappedDataFixer(DataFixers.getDataFixer()); - } - - @Override - public DataFixer buildOptimized(final Set requiredTypes, Executor executor) { - return buildUnoptimized(); - } - - @SuppressWarnings("unchecked") - 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 = PaperweightDataConverters.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 = PaperweightDataConverters.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.contains("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 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, 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.contains(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.contains(key, 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound.getList(key, 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - nbttaglist.set(j, convert(LegacyType.ITEM_INSTANCE, nbttaglist.getCompound(j), sourceVer, targetVer)); - } - } - - } - - private static class DataConverterEquipment implements DataConverter { - - DataConverterEquipment() { - } - - public int getDataVersion() { - return 100; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("Equipment", 10); - net.minecraft.nbt.ListTag nbttaglist1; - - if (!nbttaglist.isEmpty() && !cmp.contains("HandItems", 10)) { - nbttaglist1 = new net.minecraft.nbt.ListTag(); - nbttaglist1.add(nbttaglist.get(0)); - nbttaglist1.add(new net.minecraft.nbt.CompoundTag()); - cmp.put("HandItems", nbttaglist1); - } - - if (nbttaglist.size() > 1 && !cmp.contains("ArmorItem", 10)) { - nbttaglist1 = new net.minecraft.nbt.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.contains("DropChances", 9)) { - nbttaglist1 = cmp.getList("DropChances", 5); - net.minecraft.nbt.ListTag nbttaglist2; - - if (!cmp.contains("HandDropChances", 10)) { - nbttaglist2 = new net.minecraft.nbt.ListTag(); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(0))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(0.0F)); - cmp.put("HandDropChances", nbttaglist2); - } - - if (!cmp.contains("ArmorDropChances", 10)) { - nbttaglist2 = new net.minecraft.nbt.ListTag(); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(1))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(2))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(3))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(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); - } - } - - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (!cmp.contains("tag", 10)) { - return cmp; - } else { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("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.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 { - - DataInspectorEntity() { - } - - 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.contains("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; - - 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (this.key.equals(new ResourceLocation(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) { - PaperweightDataConverters.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) { - PaperweightDataConverters.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.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"; - // Paper start - materials[409] = "minecraft:prismarine_shard"; - materials[410] = "minecraft:prismarine_crystals"; - materials[411] = "minecraft:rabbit"; - materials[412] = "minecraft:cooked_rabbit"; - materials[413] = "minecraft:rabbit_stew"; - materials[414] = "minecraft:rabbit_foot"; - materials[415] = "minecraft:rabbit_hide"; - materials[416] = "minecraft:armor_stand"; - materials[423] = "minecraft:mutton"; - materials[424] = "minecraft:cooked_mutton"; - materials[425] = "minecraft:banner"; - materials[426] = "minecraft:end_crystal"; - materials[427] = "minecraft:spruce_door"; - materials[428] = "minecraft:birch_door"; - materials[429] = "minecraft:jungle_door"; - materials[430] = "minecraft:acacia_door"; - materials[431] = "minecraft:dark_oak_door"; - materials[432] = "minecraft:chorus_fruit"; - materials[433] = "minecraft:chorus_fruit_popped"; - materials[434] = "minecraft:beetroot"; - materials[435] = "minecraft:beetroot_seeds"; - materials[436] = "minecraft:beetroot_soup"; - materials[437] = "minecraft:dragon_breath"; - materials[438] = "minecraft:splash_potion"; - materials[439] = "minecraft:spectral_arrow"; - materials[440] = "minecraft:tipped_arrow"; - materials[441] = "minecraft:lingering_potion"; - materials[442] = "minecraft:shield"; - materials[443] = "minecraft:elytra"; - materials[444] = "minecraft:spruce_boat"; - materials[445] = "minecraft:birch_boat"; - materials[446] = "minecraft:jungle_boat"; - materials[447] = "minecraft:acacia_boat"; - materials[448] = "minecraft:dark_oak_boat"; - materials[449] = "minecraft:totem_of_undying"; - materials[450] = "minecraft:shulker_shell"; - materials[452] = "minecraft:iron_nugget"; - materials[453] = "minecraft:knowledge_book"; - // Paper end - } - } - - 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.contains("tag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("BlockEntityTag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); - - if (nbttagcompound2.contains("Base", 99)) { - cmp.putShort("Damage", (short) (nbttagcompound2.getShort("Base") & 15)); - if (nbttagcompound1.contains("display", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound3 = nbttagcompound1.getCompound("display"); - - if (nbttagcompound3.contains("Lore", 9)) { - net.minecraft.nbt.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.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 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.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("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.contains("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.contains("SpawnPotentials", 9)) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); - - for (int i = 0; i < nbttaglist.size(); ++i) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist.getCompound(i); - - if (nbttagcompound2.contains("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.contains("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.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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("EntityHorse".equals(cmp.getString("id")) && !cmp.contains("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.contains("Facing", 99)) { - Direction enumdirection; - - if (cmp.contains("Direction", 99)) { - enumdirection = Direction.from2DDataValue(cmp.getByte("Direction")); - cmp.putInt("TileX", cmp.getInt("TileX") + enumdirection.getStepX()); - cmp.putInt("TileY", cmp.getInt("TileY") + enumdirection.getStepY()); - cmp.putInt("TileZ", cmp.getInt("TileZ") + enumdirection.getStepZ()); - cmp.remove("Direction"); - if (flag1 && cmp.contains("ItemRotation", 99)) { - cmp.putByte("ItemRotation", (byte) (cmp.getByte("ItemRotation") * 2)); - } - } else { - enumdirection = Direction.from2DDataValue(cmp.getByte("Dir")); - cmp.remove("Dir"); - } - - cmp.putByte("Facing", (byte) enumdirection.get2DDataValue()); - } - - 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) { - net.minecraft.nbt.ListTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - while (cmp.contains("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) { - net.minecraft.nbt.ListTag nbttaglist = new net.minecraft.nbt.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.contains("pages", 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("pages", 8); - - for (int i = 0; i < nbttaglist.size(); ++i) { - String s = nbttaglist.getString(i); - Component object = null; - - if (!"null".equals(s) && !StringUtil.isNullOrEmpty(s)) { - if ((s.charAt(0) != 34 || s.charAt(s.length() - 1) != 34) && (s.charAt(0) != 123 || s.charAt(s.length() - 1) != 125)) { - object = Component.literal(s); - } else { - try { - object = GsonHelper.fromJson(DataConverterSignText.a, s, Component.class, true); - if (object == null) { - object = Component.literal(""); - } - } catch (JsonParseException jsonparseexception) { - ; - } - - if (object == null) { - try { - object = Component.Serializer.fromJson(s); - } catch (JsonParseException jsonparseexception1) { - ; - } - } - - if (object == null) { - try { - object = Component.Serializer.fromJsonLenient(s); - } catch (JsonParseException jsonparseexception2) { - ; - } - } - - if (object == null) { - object = Component.literal(s); - } - } - } else { - object = Component.literal(""); - } - - nbttaglist.set(i, net.minecraft.nbt.StringTag.valueOf(Component.Serializer.toJson(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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 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 0: - default: - break; - - 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"); - } - - 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 0: - default: - cmp.putString("id", "Horse"); - break; - - 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"); - } - - 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.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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:shulker_box".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("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.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 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(PaperweightDataConverters.class); - - DataConverterBedBlock() { - } - - public int getDataVersion() { - return 1125; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - try { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); - int i = nbttagcompound1.getInt("xPos"); - int j = nbttagcompound1.getInt("zPos"); - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("TileEntities", 10); - net.minecraft.nbt.ListTag nbttaglist1 = nbttagcompound1.getList("Sections", 10); - - for (int k = 0; k < nbttaglist1.size(); ++k) { - net.minecraft.nbt.CompoundTag 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; - net.minecraft.nbt.CompoundTag nbttagcompound3 = new net.minecraft.nbt.CompoundTag(); - - nbttagcompound3.putString("id", "bed"); - nbttagcompound3.putInt("x", i1 + (i << 4)); - nbttagcompound3.putInt("y", j1 + (b0 << 4)); - nbttagcompound3.putInt("z", k1 + (j << 4)); - nbttaglist.add(nbttagcompound3); - } - } - } - } catch (Exception exception) { - DataConverterBedBlock.a.warn("Unable to datafix Bed blocks, level format may be missing tags."); - } - - return cmp; - } - } - - private static class DataConverterBedItem implements DataConverter { - - DataConverterBedItem() { - } - - public int getDataVersion() { - return 1125; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:bed".equals(cmp.getString("id")) && cmp.getShort("Damage") == 0) { - cmp.putShort("Damage", (short) DyeColor.RED.getId()); - } - - return cmp; - } - } - - private static class DataConverterSignText implements DataConverter { - - public static final Gson a = new GsonBuilder().registerTypeAdapter(Component.class, new JsonDeserializer() { - MutableComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { - if (jsonelement.isJsonPrimitive()) { - return Component.literal(jsonelement.getAsString()); - } else if (jsonelement.isJsonArray()) { - JsonArray jsonarray = jsonelement.getAsJsonArray(); - MutableComponent ichatbasecomponent = null; - Iterator iterator = jsonarray.iterator(); - - while (iterator.hasNext()) { - JsonElement jsonelement1 = (JsonElement) iterator.next(); - MutableComponent ichatbasecomponent1 = this.a(jsonelement1, jsonelement1.getClass(), jsondeserializationcontext); - - if (ichatbasecomponent == null) { - ichatbasecomponent = ichatbasecomponent1; - } else { - ichatbasecomponent.append(ichatbasecomponent1); - } - } - - return ichatbasecomponent; - } 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); - Component object = null; - - if (!"null".equals(s1) && !StringUtil.isNullOrEmpty(s1)) { - if ((s1.charAt(0) != 34 || s1.charAt(s1.length() - 1) != 34) && (s1.charAt(0) != 123 || s1.charAt(s1.length() - 1) != 125)) { - object = Component.literal(s1); - } else { - try { - object = GsonHelper.fromJson(DataConverterSignText.a, s1, Component.class, true); - if (object == null) { - object = Component.literal(""); - } - } catch (JsonParseException jsonparseexception) { - ; - } - - if (object == null) { - try { - object = Component.Serializer.fromJson(s1); - } catch (JsonParseException jsonparseexception1) { - ; - } - } - - if (object == null) { - try { - object = Component.Serializer.fromJsonLenient(s1); - } catch (JsonParseException jsonparseexception2) { - ; - } - } - - if (object == null) { - object = Component.literal(s1); - } - } - } else { - object = Component.literal(""); - } - - nbttagcompound.putString(s, Component.Serializer.toJson(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.contains("RootVehicle", 10)) { - net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - net.minecraft.nbt.ListTag nbttaglist; - int j; - net.minecraft.nbt.CompoundTag nbttagcompound1; - - if (cmp.contains("entities", 9)) { - nbttaglist = cmp.getList("entities", 10); - - for (j = 0; j < nbttaglist.size(); ++j) { - nbttagcompound1 = (net.minecraft.nbt.CompoundTag) 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 = (net.minecraft.nbt.CompoundTag) 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (cmp.contains("Level", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); - net.minecraft.nbt.ListTag 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, (net.minecraft.nbt.CompoundTag) 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, (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.contains("Passengers", 9)) { - net.minecraft.nbt.ListTag 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 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.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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (entityVillager.equals(new ResourceLocation(cmp.getString("id"))) && cmp.contains("Offers", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Offers"); - - if (nbttagcompound1.contains("Recipes", 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("Recipes", 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (tileEntityMobSpawner.equals(new ResourceLocation(cmp.getString("id")))) { - if (cmp.contains("SpawnPotentials", 9)) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightFakePlayer.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightFakePlayer.java deleted file mode 100644 index ee7d82f09..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightFakePlayer.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 General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R3; - -import com.mojang.authlib.GameProfile; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ServerboundClientInformationPacket; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.stats.Stat; -import net.minecraft.world.MenuProvider; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.block.entity.SignBlockEntity; -import net.minecraft.world.phys.Vec3; -import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; - -import java.util.OptionalInt; -import java.util.UUID; - -class PaperweightFakePlayer extends ServerPlayer { - private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]"); - private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D); - - PaperweightFakePlayer(ServerLevel world) { - super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE); - } - - @Override - public Vec3 position() { - return ORIGIN; - } - - @Override - public void tick() { - } - - @Override - public void die(DamageSource damagesource) { - } - - @Override - public Entity changeDimension(ServerLevel worldserver, TeleportCause cause) { - return this; - } - - @Override - public OptionalInt openMenu(MenuProvider factory) { - return OptionalInt.empty(); - } - - @Override - public void updateOptions(ServerboundClientInformationPacket packet) { - } - - @Override - public void displayClientMessage(Component message, boolean actionBar) { - } - - @Override - public void awardStat(Stat stat, int amount) { - } - - @Override - public void awardStat(Stat stat) { - } - - @Override - public boolean isInvulnerableTo(DamageSource damageSource) { - return true; - } - - @Override - public void openTextEdit(SignBlockEntity sign) { - } -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightWorldNativeAccess.java deleted file mode 100644 index 424422ce6..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightWorldNativeAccess.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R3; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.world.block.BlockState; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.Tag; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.LevelChunk; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; -import org.bukkit.event.block.BlockPhysicsEvent; -import org.enginehub.linbus.tree.LinCompoundTag; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.util.Objects; - -public class PaperweightWorldNativeAccess implements WorldNativeAccess { - private static final int UPDATE = 1; - private static final int NOTIFY = 2; - - private final PaperweightAdapter adapter; - private final WeakReference world; - private SideEffectSet sideEffectSet; - - public PaperweightWorldNativeAccess(PaperweightAdapter adapter, WeakReference world) { - this.adapter = adapter; - this.world = world; - } - - private ServerLevel getWorld() { - return Objects.requireNonNull(world.get(), "The reference to the world was lost"); - } - - @Override - public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { - this.sideEffectSet = sideEffectSet; - } - - @Override - public LevelChunk getChunk(int x, int z) { - return getWorld().getChunk(x, z); - } - - @Override - public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) { - int stateId = BlockStateIdAccess.getBlockStateId(state); - return BlockStateIdAccess.isValidInternalId(stateId) - ? Block.stateById(stateId) - : ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk chunk, BlockPos position) { - return chunk.getBlockState(position); - } - - @Nullable - @Override - public net.minecraft.world.level.block.state.BlockState setBlockState(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState state) { - return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE)); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(net.minecraft.world.level.block.state.BlockState block, BlockPos position) { - return Block.updateFromNeighbourShapes(block, getWorld(), position); - } - - @Override - public BlockPos getPosition(int x, int y, int z) { - return new BlockPos(x, y, z); - } - - @Override - public void updateLightingForBlock(BlockPos position) { - getWorld().getChunkSource().getLightEngine().checkBlock(position); - } - - @Override - public boolean updateTileEntity(BlockPos position, LinCompoundTag tag) { - // We will assume that the tile entity was created for us - BlockEntity tileEntity = getWorld().getBlockEntity(position); - if (tileEntity == null) { - return false; - } - Tag nativeTag = adapter.fromNative(new CompoundTag(tag)); - PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity); - return true; - } - - @Override - public void notifyBlockUpdate(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { - if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { - getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY); - } - } - - @Override - public boolean isChunkTicking(LevelChunk chunk) { - return chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); - } - - @Override - public void markBlockChanged(LevelChunk chunk, BlockPos position) { - if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { - getWorld().getChunkSource().blockChanged(position); - } - } - - @Override - public void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { - ServerLevel world = getWorld(); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - world.updateNeighborsAt(pos, oldState.getBlock()); - } else { - // When we don't want events, manually run the physics without them. - Block block = oldState.getBlock(); - fireNeighborChanged(pos, world, block, pos.west()); - fireNeighborChanged(pos, world, block, pos.east()); - fireNeighborChanged(pos, world, block, pos.below()); - fireNeighborChanged(pos, world, block, pos.above()); - fireNeighborChanged(pos, world, block, pos.north()); - fireNeighborChanged(pos, world, block, pos.south()); - } - if (newState.hasAnalogOutputSignal()) { - world.updateNeighbourForOutputSignal(pos, newState.getBlock()); - } - } - - @Override - public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { - ServerLevel world = getWorld(); - newState.onPlace(world, pos, oldState, false); - } - - // Not sure why neighborChanged is deprecated - @SuppressWarnings("deprecation") - private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { - world.getBlockState(neighborPos).neighborChanged(world, neighborPos, block, pos, false); - } - - @Override - public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) { - ServerLevel world = getWorld(); - // a == updateNeighbors - // b == updateDiagonalNeighbors - oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - CraftWorld craftWorld = world.getWorld(); - BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState)); - world.getCraftServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - } - newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit); - newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); - } - - @Override - public void onBlockStateChange(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { - getWorld().onBlockStateChange(pos, oldState, newState); - } - - @Override - public void flush() { - - } -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightBlockMaterial.java deleted file mode 100644 index cbd1af53d..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightBlockMaterial.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; - -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.util.ReflectionUtil; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.world.registry.BlockMaterial; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.EmptyBlockGetter; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.EntityBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.Material; -import net.minecraft.world.level.material.PushReaction; -import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; - -public class PaperweightBlockMaterial implements BlockMaterial { - - private final Block block; - private final BlockState blockState; - private final Material material; - private final boolean isTranslucent; - private final CraftBlockData craftBlockData; - private final org.bukkit.Material craftMaterial; - private final int opacity; - private final CompoundTag tile; - - public PaperweightBlockMaterial(Block block) { - this(block, block.defaultBlockState()); - } - - public PaperweightBlockMaterial(Block block, BlockState blockState) { - this.block = block; - this.blockState = blockState; - this.material = blockState.getMaterial(); - this.craftBlockData = CraftBlockData.fromData(blockState); - this.craftMaterial = craftBlockData.getMaterial(); - BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, - Refraction.pickName("properties", "aP")); - this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo, - Refraction.pickName("canOcclude", "n") - ); - opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); - BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity( - BlockPos.ZERO, - blockState - ); - tile = tileEntity == null - ? null - : new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); - } - - public Block getBlock() { - return block; - } - - public BlockState getState() { - return blockState; - } - - public CraftBlockData getCraftBlockData() { - return craftBlockData; - } - - public Material getMaterial() { - return material; - } - - @Override - public boolean isAir() { - return blockState.isAir(); - } - - @Override - public boolean isFullCube() { - return craftMaterial.isOccluding(); - } - - @Override - public boolean isOpaque() { - return material.isSolidBlocking(); - } - - @Override - public boolean isPowerSource() { - return blockState.isSignalSource(); - } - - @Override - public boolean isLiquid() { - return material.isLiquid(); - } - - @Override - public boolean isSolid() { - return material.isSolid(); - } - - @Override - public float getHardness() { - return craftBlockData.getState().destroySpeed; - } - - @Override - public float getResistance() { - return block.getExplosionResistance(); - } - - @Override - public float getSlipperiness() { - return block.getFriction(); - } - - @Override - public int getLightValue() { - return blockState.getLightEmission(); - } - - @Override - public int getLightOpacity() { - return opacity; - } - - @Override - public boolean isFragileWhenPushed() { - return material.getPushReaction() == PushReaction.DESTROY; - } - - @Override - public boolean isUnpushable() { - return material.getPushReaction() == PushReaction.BLOCK; - } - - @Override - public boolean isTicksRandomly() { - return block.isRandomlyTicking(blockState); - } - - @Override - public boolean isMovementBlocker() { - return material.isSolid(); - } - - @Override - public boolean isBurnable() { - return material.isFlammable(); - } - - @Override - public boolean isToolRequired() { - // Removed in 1.16.1, this is not present in higher versions - return false; - } - - @Override - public boolean isReplacedDuringPlacement() { - return material.isReplaceable(); - } - - @Override - public boolean isTranslucent() { - return isTranslucent; - } - - @Override - public boolean hasContainer() { - return block instanceof EntityBlock; - } - - @Override - public boolean isTile() { - return block instanceof EntityBlock; - } - - @Override - public CompoundTag getDefaultTile() { - return tile; - } - - @Override - public int getMapColor() { - // rgb field - return material.getColor().col; - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweAdapter.java deleted file mode 100644 index 0b90d942a..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweAdapter.java +++ /dev/null @@ -1,614 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; - -import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; -import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.entity.LazyBaseEntity; -import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IBatchProcessor; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; -import com.fastasyncworldedit.core.util.NbtUtils; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R3.PaperweightAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.regen.PaperweightRegen; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; -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.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.world.RegenOptions; -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.block.BlockType; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import com.sk89q.worldedit.world.entity.EntityType; -import com.sk89q.worldedit.world.item.ItemType; -import com.sk89q.worldedit.world.registry.BlockMaterial; -import io.papermc.lib.PaperLib; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Registry; -import net.minecraft.core.WritableRegistry; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.util.StringRepresentable; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.DirectionProperty; -import net.minecraft.world.level.chunk.LevelChunk; -import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.World; -import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_19_R3.CraftServer; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_19_R3.util.CraftNamespacedKey; -import org.bukkit.entity.Player; -import org.enginehub.linbus.tree.LinCompoundTag; -import org.enginehub.linbus.tree.LinStringTag; -import org.enginehub.linbus.tree.LinTag; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.OptionalInt; -import java.util.Set; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static net.minecraft.core.registries.Registries.BIOME; - -public final class PaperweightFaweAdapter extends FaweAdapter { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; - - static { - try { - CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE = ChunkHolder.class.getDeclaredMethod("wasAccessibleSinceLastSave"); - } catch (NoSuchMethodException ignored) { // may not be present in newer paper versions - } - } - - private final PaperweightAdapter parent; - // ------------------------------------------------------------------------ - // Code that may break between versions of Minecraft - // ------------------------------------------------------------------------ - private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil(); - private char[] ibdToStateOrdinal = null; - private int[] ordinalToIbdID = null; - private boolean initialised = false; - private Map>> allBlockProperties = null; - - public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { - this.parent = new PaperweightAdapter(); - } - - @Nullable - private static String getEntityId(Entity entity) { - ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType()); - return resourceLocation == null ? null : resourceLocation.toString(); - } - - @Override - public BukkitImplAdapter getParent() { - return parent; - } - - private synchronized boolean init() { - if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) { - return false; - } - ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size - ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size - for (int i = 0; i < ibdToStateOrdinal.length; i++) { - BlockState blockState = BlockTypesCache.states[i]; - PaperweightBlockMaterial material = (PaperweightBlockMaterial) blockState.getMaterial(); - int id = Block.BLOCK_STATE_REGISTRY.getId(material.getState()); - char ordinal = blockState.getOrdinalChar(); - ibdToStateOrdinal[id] = ordinal; - ordinalToIbdID[ordinal] = id; - } - Map>> properties = new HashMap<>(); - try { - for (Field field : BlockStateProperties.class.getDeclaredFields()) { - Object obj = field.get(null); - if (!(obj instanceof net.minecraft.world.level.block.state.properties.Property state)) { - continue; - } - Property property; - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - property = new BooleanProperty( - state.getName(), - (List) ImmutableList.copyOf(state.getPossibleValues()) - ); - } else if (state instanceof DirectionProperty) { - property = new DirectionalProperty( - state.getName(), - state - .getPossibleValues() - .stream() - .map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase())) - .collect(Collectors.toList()) - ); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - property = new EnumProperty( - state.getName(), - state - .getPossibleValues() - .stream() - .map(e -> ((StringRepresentable) e).getSerializedName()) - .collect(Collectors.toList()) - ); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - property = new IntegerProperty( - state.getName(), - (List) ImmutableList.copyOf(state.getPossibleValues()) - ); - } else { - throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state - .getClass() - .getSimpleName()); - } - properties.compute(property.getName().toLowerCase(Locale.ROOT), (k, v) -> { - if (v == null) { - v = new ArrayList<>(Collections.singletonList(property)); - } else { - v.add(property); - } - return v; - }); - } - } catch (IllegalAccessException e) { - e.printStackTrace(); - } finally { - allBlockProperties = ImmutableMap.copyOf(properties); - } - initialised = true; - return true; - } - - @Override - public BlockMaterial getMaterial(BlockType blockType) { - Block block = getBlock(blockType); - return new PaperweightBlockMaterial(block); - } - - @Override - public synchronized BlockMaterial getMaterial(BlockState state) { - net.minecraft.world.level.block.state.BlockState blockState = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState(); - return new PaperweightBlockMaterial(blockState.getBlock(), blockState); - } - - public Block getBlock(BlockType blockType) { - return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK) - .get(new ResourceLocation(blockType.getNamespace(), blockType.getResource())); - } - - @Deprecated - @Override - public BlockState getBlock(Location location) { - Preconditions.checkNotNull(location); - - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - final ServerLevel handle = getServerLevel(location.getWorld()); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - BlockState state = adapt(blockData); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - return state; - } - - @Override - public BaseBlock getFullBlock(final Location location) { - Preconditions.checkNotNull(location); - - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = getServerLevel(location.getWorld()); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - BlockState state = adapt(blockData); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - if (state.getBlockType().getMaterial().hasContainer()) { - - // Read the NBT data - BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); - if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); - return state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); - } - } - - return state.toBaseBlock(); - } - - @Override - public Set getSupportedSideEffects() { - return SideEffectSet.defaults().getSideEffectsToApply(); - } - - @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); - } - - @Override - public BaseEntity getEntity(org.bukkit.entity.Entity entity) { - Preconditions.checkNotNull(entity); - - CraftEntity craftEntity = ((CraftEntity) entity); - Entity mcEntity = craftEntity.getHandle(); - - String id = getEntityId(mcEntity); - - if (id != null) { - EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); - Supplier saveTag = () -> { - final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(mcEntity, minecraftTag); - //add Id for AbstractChangeSet to work - final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag); - final Map> tags = NbtUtils.getLinCompoundTagValues(tag); - tags.put("Id", LinStringTag.of(id)); - return LinCompoundTag.of(tags); - }; - return new LazyBaseEntity(type, saveTag); - } else { - return null; - } - } - - @Override - public Component getRichBlockName(BlockType blockType) { - return parent.getRichBlockName(blockType); - } - - @Override - public Component getRichItemName(ItemType itemType) { - return parent.getRichItemName(itemType); - } - - @Override - public Component getRichItemName(BaseItemStack itemStack) { - return parent.getRichItemName(itemStack); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockState state) { - PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); - net.minecraft.world.level.block.state.BlockState mcState = material.getCraftBlockData().getState(); - return OptionalInt.of(Block.BLOCK_STATE_REGISTRY.getId(mcState)); - } - - @Override - public BlockState adapt(BlockData blockData) { - CraftBlockData cbd = ((CraftBlockData) blockData); - net.minecraft.world.level.block.state.BlockState ibd = cbd.getState(); - return adapt(ibd); - } - - public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) { - return BlockTypesCache.states[adaptToChar(blockState)]; - } - - public char adaptToChar(net.minecraft.world.level.block.state.BlockState blockState) { - int id = Block.BLOCK_STATE_REGISTRY.getId(blockState); - if (initialised) { - return ibdToStateOrdinal[id]; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - try { - init(); - return ibdToStateOrdinal[id]; - } catch (ArrayIndexOutOfBoundsException e1) { - LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!", - blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1 - ); - return BlockTypesCache.ReservedIDs.AIR; - } - } - } - - public char ibdIDToOrdinal(int id) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - init(); - return ibdToStateOrdinal[id]; - } - } - - @Override - public char[] getIbdToStateOrdinal() { - if (initialised) { - return ibdToStateOrdinal; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal; - } - init(); - return ibdToStateOrdinal; - } - } - - public int ordinalToIbdID(char ordinal) { - if (initialised) { - return ordinalToIbdID[ordinal]; - } - synchronized (this) { - if (initialised) { - return ordinalToIbdID[ordinal]; - } - init(); - return ordinalToIbdID[ordinal]; - } - } - - @Override - public int[] getOrdinalToIbdID() { - if (initialised) { - return ordinalToIbdID; - } - synchronized (this) { - if (initialised) { - return ordinalToIbdID; - } - init(); - return ordinalToIbdID; - } - } - - @Override - public > BlockData adapt(B state) { - PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); - return material.getCraftBlockData(); - } - - @Override - public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { - ServerLevel nmsWorld = getServerLevel(world); - ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); - if (map != null && wasAccessibleSinceLastSave(map)) { - boolean flag = false; - // PlayerChunk.d players = map.players; - Stream stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag) - */ Stream.empty(); - - ServerPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle(); - stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer) - .forEach(entityPlayer -> { - synchronized (chunkPacket) { - ClientboundLevelChunkWithLightPacket nmsPacket = (ClientboundLevelChunkWithLightPacket) chunkPacket.getNativePacket(); - if (nmsPacket == null) { - nmsPacket = mapUtil.create(this, chunkPacket); - chunkPacket.setNativePacket(nmsPacket); - } - try { - FaweCache.INSTANCE.CHUNK_FLAG.get().set(true); - entityPlayer.connection.send(nmsPacket); - } finally { - FaweCache.INSTANCE.CHUNK_FLAG.get().set(false); - } - } - }); - } - } - - @Override - public Map> getProperties(BlockType blockType) { - return getParent().getProperties(blockType); - } - - @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) { - int internalId = BlockStateIdAccess.getBlockStateId(blockState); - net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); - return blockState1.hasPostProcess( - getServerLevel(world), - new BlockPos(blockVector3.x(), blockVector3.y(), blockVector3.z()) - ); - } - - @Override - public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { - ItemStack stack = new ItemStack( - DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM) - .get(ResourceLocation.tryParse(baseItemStack.getType().id())), - baseItemStack.getAmount() - ); - stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()))); - return CraftItemStack.asCraftMirror(stack); - } - - @Override - protected void preCaptureStates(final ServerLevel serverLevel) { - serverLevel.captureTreeGeneration = true; - serverLevel.captureBlockStates = true; - } - - @Override - protected List getCapturedBlockStatesCopy(final ServerLevel serverLevel) { - return new ArrayList<>(serverLevel.capturedBlockStates.values()); - } - - @Override - protected void postCaptureBlockStates(final ServerLevel serverLevel) { - serverLevel.captureBlockStates = false; - serverLevel.captureTreeGeneration = false; - serverLevel.capturedBlockStates.clear(); - } - - @Override - protected ServerLevel getServerLevel(final World world) { - return ((CraftWorld) world).getHandle(); - } - - @Override - public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { - final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); - final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); - weStack.setNbt((LinCompoundTag) toNativeLin(nmsStack.getTag())); - return weStack; - } - - @Override - public Tag toNative(net.minecraft.nbt.Tag foreign) { - return parent.toNative(foreign); - } - - @Override - public net.minecraft.nbt.Tag fromNative(Tag foreign) { - if (foreign instanceof PaperweightLazyCompoundTag) { - return ((PaperweightLazyCompoundTag) foreign).get(); - } - return parent.fromNative(foreign); - } - - @Override - public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { - return new PaperweightRegen(bukkitWorld, region, target, options).regenerate(); - } - - @Override - public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { - return new PaperweightGetBlocks(world, chunkX, chunkZ); - } - - @Override - public int getInternalBiomeId(BiomeType biomeType) { - final Registry registry = MinecraftServer - .getServer() - .registryAccess() - .registryOrThrow(BIOME); - ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.id()); - Biome biome = registry.get(resourceLocation); - return registry.getId(biome); - } - - @Override - public Iterable getRegisteredBiomes() { - WritableRegistry biomeRegistry = (WritableRegistry) ((CraftServer) Bukkit.getServer()) - .getServer() - .registryAccess() - .registryOrThrow(BIOME); - List keys = biomeRegistry.stream() - .map(biomeRegistry::getKey).filter(Objects::nonNull).toList(); - List namespacedKeys = new ArrayList<>(); - for (ResourceLocation key : keys) { - try { - namespacedKeys.add(CraftNamespacedKey.fromMinecraft(key)); - } catch (IllegalArgumentException e) { - LOGGER.error("Error converting biome key {}", key.toString(), e); - } - } - return namespacedKeys; - } - - @Override - public RelighterFactory getRelighterFactory() { - if (PaperLib.isPaper()) { - return new PaperweightStarlightRelighterFactory(); - } else { - return new NMSRelighterFactory(); - } - } - - @Override - public Map>> getAllProperties() { - if (initialised) { - return allBlockProperties; - } - synchronized (this) { - if (initialised) { - return allBlockProperties; - } - init(); - return allBlockProperties; - } - } - - @Override - public IBatchProcessor getTickingPostProcessor() { - return new PaperweightPostProcessor(); - } - - private boolean wasAccessibleSinceLastSave(ChunkHolder holder) { - if (!PaperLib.isPaper() || !PaperweightPlatformAdapter.POST_CHUNK_REWRITE) { - try { - return (boolean) CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE.invoke(holder); - } catch (IllegalAccessException | InvocationTargetException ignored) { - // fall-through - } - } - // Papers new chunk system has no related replacement - therefor we assume true. - return true; - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweWorldNativeAccess.java deleted file mode 100644 index 0c57f9ca6..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweWorldNativeAccess.java +++ /dev/null @@ -1,292 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; - -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.math.IntPair; -import com.fastasyncworldedit.core.util.TaskManager; -import com.fastasyncworldedit.core.util.task.RunnableVal; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.world.block.BlockState; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.LevelChunk; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; -import org.bukkit.event.block.BlockPhysicsEvent; -import org.enginehub.linbus.tree.LinCompoundTag; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.util.Collections; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; - -public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess { - - private static final int UPDATE = 1; - private static final int NOTIFY = 2; - private static final Direction[] NEIGHBOUR_ORDER = { - Direction.EAST, - Direction.WEST, - Direction.DOWN, - Direction.UP, - Direction.NORTH, - Direction.SOUTH - }; - private final PaperweightFaweAdapter paperweightFaweAdapter; - private final WeakReference level; - private final AtomicInteger lastTick; - private final Set cachedChanges = new HashSet<>(); - private final Set cachedChunksToSend = new HashSet<>(); - private SideEffectSet sideEffectSet; - - public PaperweightFaweWorldNativeAccess(PaperweightFaweAdapter paperweightFaweAdapter, WeakReference level) { - this.paperweightFaweAdapter = paperweightFaweAdapter; - this.level = level; - // Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging. - // - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway. - this.lastTick = new AtomicInteger(MinecraftServer.currentTick); - } - - private Level getLevel() { - return Objects.requireNonNull(level.get(), "The reference to the world was lost"); - } - - @Override - public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { - this.sideEffectSet = sideEffectSet; - } - - @Override - public LevelChunk getChunk(int x, int z) { - return getLevel().getChunk(x, z); - } - - @Override - public net.minecraft.world.level.block.state.BlockState toNative(BlockState blockState) { - int stateId = paperweightFaweAdapter.ordinalToIbdID(blockState.getOrdinalChar()); - return BlockStateIdAccess.isValidInternalId(stateId) - ? Block.stateById(stateId) - : ((CraftBlockData) BukkitAdapter.adapt(blockState)).getState(); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk levelChunk, BlockPos blockPos) { - return levelChunk.getBlockState(blockPos); - } - - @Nullable - @Override - public synchronized net.minecraft.world.level.block.state.BlockState setBlockState( - LevelChunk levelChunk, BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState blockState - ) { - int currentTick = MinecraftServer.currentTick; - if (Fawe.isMainThread()) { - return levelChunk.setBlockState(blockPos, blockState, - this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE) - ); - } - // Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( ) - cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState)); - cachedChunksToSend.add(new IntPair(levelChunk.locX, levelChunk.locZ)); - boolean nextTick = lastTick.get() > currentTick; - if (nextTick || cachedChanges.size() >= 1024) { - if (nextTick) { - lastTick.set(currentTick); - } - flushAsync(nextTick); - } - return blockState; - } - - @Override - public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition( - net.minecraft.world.level.block.state.BlockState blockState, - BlockPos blockPos - ) { - return Block.updateFromNeighbourShapes(blockState, getLevel(), blockPos); - } - - @Override - public BlockPos getPosition(int x, int y, int z) { - return new BlockPos(x, y, z); - } - - @Override - public void updateLightingForBlock(BlockPos blockPos) { - getLevel().getChunkSource().getLightEngine().checkBlock(blockPos); - } - - @Override - public boolean updateTileEntity(BlockPos blockPos, LinCompoundTag tag) { - // We will assume that the tile entity was created for us, - // though we do not do this on the other versions - BlockEntity blockEntity = getLevel().getBlockEntity(blockPos); - if (blockEntity == null) { - return false; - } - net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeLin(tag); - blockEntity.load((CompoundTag) nativeTag); - return true; - } - - @Override - public void notifyBlockUpdate( - LevelChunk levelChunk, BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { - getLevel().sendBlockUpdated(blockPos, oldState, newState, UPDATE | NOTIFY); - } - } - - @Override - public boolean isChunkTicking(LevelChunk levelChunk) { - return levelChunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); - } - - @Override - public void markBlockChanged(LevelChunk levelChunk, BlockPos blockPos) { - if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { - ((ServerChunkCache) getLevel().getChunkSource()).blockChanged(blockPos); - } - } - - @Override - public void notifyNeighbors( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - Level level = getLevel(); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - level.blockUpdated(blockPos, oldState.getBlock()); - } else { - // When we don't want events, manually run the physics without them. - // Un-nest neighbour updating - for (Direction direction : NEIGHBOUR_ORDER) { - BlockPos shifted = blockPos.relative(direction); - level.getBlockState(shifted).neighborChanged(level, shifted, oldState.getBlock(), blockPos, false); - } - } - if (newState.hasAnalogOutputSignal()) { - level.updateNeighbourForOutputSignal(blockPos, newState.getBlock()); - } - } - - @Override - public void updateNeighbors( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState, - int recursionLimit - ) { - Level level = getLevel(); - // a == updateNeighbors - // b == updateDiagonalNeighbors - oldState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - CraftWorld craftWorld = level.getWorld(); - if (craftWorld != null) { - BlockPhysicsEvent event = new BlockPhysicsEvent( - craftWorld.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()), - CraftBlockData.fromData(newState) - ); - level.getCraftServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - } - } - newState.triggerEvent(level, blockPos, NOTIFY, recursionLimit); - newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); - } - - @Override - public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { - Level world = getLevel(); - newState.onPlace(world, pos, oldState, false); - } - - @Override - public void onBlockStateChange( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - getLevel().onBlockStateChange(blockPos, oldState, newState); - } - - private synchronized void flushAsync(final boolean sendChunks) { - final Set changes = Set.copyOf(cachedChanges); - cachedChanges.clear(); - final Set toSend; - if (sendChunks) { - toSend = Set.copyOf(cachedChunksToSend); - cachedChunksToSend.clear(); - } else { - toSend = Collections.emptySet(); - } - RunnableVal runnableVal = new RunnableVal<>() { - @Override - public void run(Object value) { - changes.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, - sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) - )); - if (!sendChunks) { - return; - } - for (IntPair chunk : toSend) { - PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z()); - } - } - }; - TaskManager.taskManager().async(() -> TaskManager.taskManager().sync(runnableVal)); - } - - @Override - public synchronized void flush() { - RunnableVal runnableVal = new RunnableVal<>() { - @Override - public void run(Object value) { - cachedChanges.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, - sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) - )); - for (IntPair chunk : cachedChunksToSend) { - PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z()); - } - } - }; - if (Fawe.isMainThread()) { - runnableVal.run(); - } else { - TaskManager.taskManager().sync(runnableVal); - } - cachedChanges.clear(); - cachedChunksToSend.clear(); - } - - private record CachedChange( - LevelChunk levelChunk, - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState blockState - ) { - - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java deleted file mode 100644 index c3d4388e9..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java +++ /dev/null @@ -1,1187 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; - -import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; -import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; -import com.fastasyncworldedit.core.math.BitArrayUnstretched; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.fastasyncworldedit.core.queue.implementation.QueueHandler; -import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.collection.AdaptedMap; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.internal.Constants; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.BiomeTypes; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import io.papermc.lib.PaperLib; -import io.papermc.paper.event.block.BeaconDeactivatedEvent; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.IdMap; -import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; -import net.minecraft.nbt.IntTag; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.util.BitStorage; -import net.minecraft.util.ZeroBitStorage; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.entity.BeaconBlockEntity; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.HashMapPalette; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.LinearPalette; -import net.minecraft.world.level.chunk.Palette; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.level.lighting.LevelLightEngine; -import org.apache.logging.log4j.Logger; -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import javax.annotation.Nonnull; -import java.util.AbstractSet; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Future; -import java.util.concurrent.Semaphore; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static net.minecraft.core.registries.Registries.BIOME; - -public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private static final Function posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); - private static final Function nmsTile2We = - tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); - private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin - .getInstance() - .getBukkitImplAdapter()); - private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); - private final ReentrantLock callLock = new ReentrantLock(); - private final ServerLevel serverLevel; - private final int chunkX; - private final int chunkZ; - private final int minHeight; - private final int maxHeight; - private final int minSectionPosition; - private final int maxSectionPosition; - private final Registry biomeRegistry; - private final IdMap> biomeHolderIdMap; - private final ConcurrentHashMap copies = new ConcurrentHashMap<>(); - private final Object sendLock = new Object(); - private LevelChunkSection[] sections; - private LevelChunk levelChunk; - private DataLayer[] blockLight; - private DataLayer[] skyLight; - private boolean createCopy = false; - private boolean forceLoadSections = true; - private boolean lightUpdate = false; - private int copyKey = 0; - - public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { - this(((CraftWorld) world).getHandle(), chunkX, chunkZ); - } - - public PaperweightGetBlocks(ServerLevel serverLevel, int chunkX, int chunkZ) { - super(serverLevel.getMinBuildHeight() >> 4, (serverLevel.getMaxBuildHeight() - 1) >> 4); - this.serverLevel = serverLevel; - this.chunkX = chunkX; - this.chunkZ = chunkZ; - this.minHeight = serverLevel.getMinBuildHeight(); - this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. - this.minSectionPosition = minHeight >> 4; - this.maxSectionPosition = maxHeight >> 4; - this.skyLight = new DataLayer[getSectionCount()]; - this.blockLight = new DataLayer[getSectionCount()]; - this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME); - this.biomeHolderIdMap = biomeRegistry.asHolderIdMap(); - } - - public int getChunkX() { - return chunkX; - } - - public int getChunkZ() { - return chunkZ; - } - - @Override - public boolean isCreateCopy() { - return createCopy; - } - - @Override - public int setCreateCopy(boolean createCopy) { - if (!callLock.isHeldByCurrentThread()) { - throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); - } - this.createCopy = createCopy; - // Increment regardless of whether copy will be created or not to return null from getCopy() - return ++this.copyKey; - } - - @Override - public IChunkGet getCopy(final int key) { - return copies.remove(key); - } - - @Override - public void lockCall() { - this.callLock.lock(); - } - - @Override - public void unlockCall() { - this.callLock.unlock(); - } - - @Override - public void setLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { - if (light != null) { - lightUpdate = true; - try { - fillLightNibble(light, LightLayer.BLOCK, minSectionPosition, maxSectionPosition); - } catch (Throwable e) { - e.printStackTrace(); - } - } - } - - @Override - public void setSkyLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { - if (light != null) { - lightUpdate = true; - try { - fillLightNibble(light, LightLayer.SKY, minSectionPosition, maxSectionPosition); - } catch (Throwable e) { - e.printStackTrace(); - } - } - } - - @Override - public void setHeightmapToGet(HeightMapType type, int[] data) { - // height + 1 to match server internal - BitArrayUnstretched bitArray = new BitArrayUnstretched(MathMan.log2nlz(getChunk().getHeight() + 1), 256); - bitArray.fromRaw(data); - Heightmap.Types nativeType = Heightmap.Types.valueOf(type.name()); - Heightmap heightMap = getChunk().heightmaps.get(nativeType); - heightMap.setRawData(getChunk(), nativeType, bitArray.getData()); - } - - @Override - public int getMaxY() { - return maxHeight; - } - - @Override - public int getMinY() { - return minHeight; - } - - @Override - public BiomeType getBiomeType(int x, int y, int z) { - LevelChunkSection section = getSections(false)[(y >> 4) - getMinSectionPosition()]; - Holder biomes = section.getNoiseBiome(x >> 2, (y & 15) >> 2, z >> 2); - return PaperweightPlatformAdapter.adapt(biomes, serverLevel); - } - - @Override - public void removeSectionLighting(int layer, boolean sky) { - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.BLOCK).getDataLayerData( - sectionPos); - if (dataLayer != null) { - lightUpdate = true; - synchronized (dataLayer) { - byte[] bytes = dataLayer.getData(); - Arrays.fill(bytes, (byte) 0); - } - } - if (sky) { - SectionPos sectionPos1 = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer1 = serverLevel - .getChunkSource() - .getLightEngine() - .getLayerListener(LightLayer.SKY) - .getDataLayerData(sectionPos1); - if (dataLayer1 != null) { - lightUpdate = true; - synchronized (dataLayer1) { - byte[] bytes = dataLayer1.getData(); - Arrays.fill(bytes, (byte) 0); - } - } - } - } - - @Override - public CompoundTag getTile(int x, int y, int z) { - BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( - chunkX << 4), y, (z & 15) + ( - chunkZ << 4))); - if (blockEntity == null) { - return null; - } - return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)); - } - - @Override - public Map getTiles() { - Map nmsTiles = getChunk().getBlockEntities(); - if (nmsTiles.isEmpty()) { - return Collections.emptyMap(); - } - return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); - } - - @Override - public int getSkyLight(int x, int y, int z) { - int layer = y >> 4; - int alayer = layer - getMinSectionPosition(); - if (skyLight[alayer] == null) { - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = - serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.SKY).getDataLayerData(sectionPos); - // If the server hasn't generated the section's NibbleArray yet, it will be null - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. - Arrays.fill(LAYER_COUNT, (byte) 15); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( - LightLayer.BLOCK, - sectionPos, - dataLayer, - true - ); - } - skyLight[alayer] = dataLayer; - } - return skyLight[alayer].get(x & 15, y & 15, z & 15); - } - - @Override - public int getEmittedLight(int x, int y, int z) { - int layer = y >> 4; - int alayer = layer - getMinSectionPosition(); - if (blockLight[alayer] == null) { - serverLevel.getRawBrightness(new BlockPos(1, 1, 1), 5); - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = serverLevel - .getChunkSource() - .getLightEngine() - .getLayerListener(LightLayer.BLOCK) - .getDataLayerData(sectionPos); - // If the server hasn't generated the section's DataLayer yet, it will be null - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. - Arrays.fill(LAYER_COUNT, (byte) 15); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos, - dataLayer, true - ); - } - blockLight[alayer] = dataLayer; - } - return blockLight[alayer].get(x & 15, y & 15, z & 15); - } - - @Override - public int[] getHeightMap(HeightMapType type) { - long[] longArray = getChunk().heightmaps.get(Heightmap.Types.valueOf(type.name())).getRawData(); - BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256, longArray); - return bitArray.toRaw(new int[256]); - } - - @Override - public CompoundTag getEntity(UUID uuid) { - Entity entity = serverLevel.getEntity(uuid); - if (entity != null) { - org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); - return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); - } - for (CompoundTag tag : getEntities()) { - if (uuid.equals(tag.getUUID())) { - return tag; - } - } - return null; - } - - @Override - public Set getEntities() { - ensureLoaded(serverLevel, chunkX, chunkZ); - List entities = PaperweightPlatformAdapter.getEntities(getChunk()); - if (entities.isEmpty()) { - return Collections.emptySet(); - } - int size = entities.size(); - return new AbstractSet<>() { - @Override - public int size() { - return size; - } - - @Override - public boolean isEmpty() { - return false; - } - - @Override - public boolean contains(Object get) { - if (!(get instanceof CompoundTag getTag)) { - return false; - } - UUID getUUID = getTag.getUUID(); - for (Entity entity : entities) { - UUID uuid = entity.getUUID(); - if (uuid.equals(getUUID)) { - return true; - } - } - return false; - } - - @Nonnull - @Override - public Iterator iterator() { - Iterable result = entities.stream().map(input -> { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(input, tag); - return (CompoundTag) adapter.toNative(tag); - }).collect(Collectors.toList()); - return result.iterator(); - } - }; - } - - private void removeEntity(Entity entity) { - entity.discard(); - } - - public LevelChunk ensureLoaded(ServerLevel nmsWorld, int chunkX, int chunkZ) { - return PaperweightPlatformAdapter.ensureLoaded(nmsWorld, chunkX, chunkZ); - } - - @Override - @SuppressWarnings("rawtypes") - public synchronized > T call(IChunkSet set, Runnable finalizer) { - if (!callLock.isHeldByCurrentThread()) { - throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked."); - } - forceLoadSections = false; - PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; - if (createCopy) { - if (copies.containsKey(copyKey)) { - throw new IllegalStateException("Copy key already used."); - } - copies.put(copyKey, copy); - } - try { - ServerLevel nmsWorld = serverLevel; - LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); - - // Remove existing tiles. Create a copy so that we can remove blocks - Map chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); - List beacons = null; - if (!chunkTiles.isEmpty()) { - for (Map.Entry entry : chunkTiles.entrySet()) { - final BlockPos pos = entry.getKey(); - final int lx = pos.getX() & 15; - final int ly = pos.getY(); - final int lz = pos.getZ() & 15; - final int layer = ly >> 4; - if (!set.hasSection(layer)) { - continue; - } - - int ordinal = set.getBlock(lx, ly, lz).getOrdinal(); - if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) { - BlockEntity tile = entry.getValue(); - if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) { - if (beacons == null) { - beacons = new ArrayList<>(); - } - beacons.add(tile); - PaperweightPlatformAdapter.removeBeacon(tile, nmsChunk); - continue; - } - nmsChunk.removeBlockEntity(tile.getBlockPos()); - if (createCopy) { - copy.storeTile(tile); - } - } - } - } - final BiomeType[][] biomes = set.getBiomes(); - - int bitMask = 0; - synchronized (nmsChunk) { - LevelChunkSection[] levelChunkSections = nmsChunk.getSections(); - - for (int layerNo = getMinSectionPosition(); layerNo <= getMaxSectionPosition(); layerNo++) { - - int getSectionIndex = layerNo - getMinSectionPosition(); - int setSectionIndex = layerNo - set.getMinSectionPosition(); - - if (!set.hasSection(layerNo)) { - // No blocks, but might be biomes present. Handle this lazily. - if (biomes == null) { - continue; - } - if (layerNo < set.getMinSectionPosition() || layerNo > set.getMaxSectionPosition()) { - continue; - } - if (biomes[setSectionIndex] != null) { - synchronized (super.sectionLocks[getSectionIndex]) { - LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; - if (createCopy && existingSection != null) { - copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); - } - - if (existingSection == null) { - PalettedContainer> biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer( - biomes[setSectionIndex], - biomeHolderIdMap - ); - LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection( - layerNo, - new char[4096], - adapter, - biomeRegistry, - biomeData - ); - if (PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - null, - newSection, - getSectionIndex - )) { - updateGet(nmsChunk, levelChunkSections, newSection, new char[4096], getSectionIndex); - continue; - } else { - existingSection = levelChunkSections[getSectionIndex]; - if (existingSection == null) { - LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - getSectionIndex - ); - continue; - } - } - } else { - PalettedContainer> paletteBiomes = setBiomesToPalettedContainer( - biomes, - setSectionIndex, - existingSection.getBiomes() - ); - if (paletteBiomes != null) { - PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes); - } - } - } - } - continue; - } - - bitMask |= 1 << getSectionIndex; - - // setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to - // this chunk GET when #updateGet is called. Future dords, please listen this time. - char[] tmp = set.load(layerNo); - char[] setArr = new char[tmp.length]; - System.arraycopy(tmp, 0, setArr, 0, tmp.length); - - // synchronise on internal section to avoid circular locking with a continuing edit if the chunk was - // submitted to keep loaded internal chunks to queue target size. - synchronized (super.sectionLocks[getSectionIndex]) { - - LevelChunkSection newSection; - LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; - // Don't attempt to tick section whilst we're editing - if (existingSection != null) { - PaperweightPlatformAdapter.clearCounts(existingSection); - if (PaperLib.isPaper()) { - existingSection.tickingList.clear(); - } - } - - if (createCopy) { - char[] tmpLoad = loadPrivately(layerNo); - char[] copyArr = new char[4096]; - System.arraycopy(tmpLoad, 0, copyArr, 0, 4096); - copy.storeSection(getSectionIndex, copyArr); - if (biomes != null && existingSection != null) { - copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); - } - } - - if (existingSection == null) { - PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( - biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), - PalettedContainer.Strategy.SECTION_BIOMES, - null - ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); - newSection = PaperweightPlatformAdapter.newChunkSection( - layerNo, - setArr, - adapter, - biomeRegistry, - biomeData - ); - if (PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - null, - newSection, - getSectionIndex - )) { - updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); - continue; - } else { - existingSection = levelChunkSections[getSectionIndex]; - if (existingSection == null) { - LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - getSectionIndex - ); - continue; - } - } - } - - //ensure that the server doesn't try to tick the chunksection while we're editing it. (Again) - PaperweightPlatformAdapter.clearCounts(existingSection); - if (PaperLib.isPaper()) { - existingSection.tickingList.clear(); - } - DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); - - // Synchronize to prevent further acquisitions - synchronized (lock) { - lock.acquire(); // Wait until we have the lock - lock.release(); - try { - sectionLock.writeLock().lock(); - if (this.getChunk() != nmsChunk) { - this.levelChunk = nmsChunk; - this.sections = null; - this.reset(); - } else if (existingSection != getSections(false)[getSectionIndex]) { - this.sections[getSectionIndex] = existingSection; - this.reset(); - } else if (!Arrays.equals( - update(getSectionIndex, new char[4096], true), - loadPrivately(layerNo) - )) { - this.reset(layerNo); - /*} else if (lock.isModified()) { - this.reset(layerNo);*/ - } - } finally { - sectionLock.writeLock().unlock(); - } - - PalettedContainer> biomeData = setBiomesToPalettedContainer( - biomes, - setSectionIndex, - existingSection.getBiomes() - ); - - newSection = PaperweightPlatformAdapter.newChunkSection( - layerNo, - this::loadPrivately, - setArr, - adapter, - biomeRegistry, - biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() - ); - if (!PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - existingSection, - newSection, - getSectionIndex - )) { - LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - getSectionIndex - ); - } else { - updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); - } - } - } - } - - Map heightMaps = set.getHeightMaps(); - for (Map.Entry entry : heightMaps.entrySet()) { - PaperweightGetBlocks.this.setHeightmapToGet(entry.getKey(), entry.getValue()); - } - PaperweightGetBlocks.this.setLightingToGet( - set.getLight(), - set.getMinSectionPosition(), - set.getMaxSectionPosition() - ); - PaperweightGetBlocks.this.setSkyLightingToGet( - set.getSkyLight(), - set.getMinSectionPosition(), - set.getMaxSectionPosition() - ); - - Runnable[] syncTasks = null; - - int bx = chunkX << 4; - int bz = chunkZ << 4; - - // Call beacon deactivate events here synchronously - // list will be null on spigot, so this is an implicit isPaper check - if (beacons != null && !beacons.isEmpty()) { - final List finalBeacons = beacons; - - syncTasks = new Runnable[4]; - - syncTasks[3] = () -> { - for (BlockEntity beacon : finalBeacons) { - BeaconBlockEntity.playSound(beacon.getLevel(), beacon.getBlockPos(), SoundEvents.BEACON_DEACTIVATE); - new BeaconDeactivatedEvent(CraftBlock.at(beacon.getLevel(), beacon.getBlockPos())).callEvent(); - } - }; - } - - Set entityRemoves = set.getEntityRemoves(); - if (entityRemoves != null && !entityRemoves.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[3]; - } - - syncTasks[2] = () -> { - Set entitiesRemoved = new HashSet<>(); - final List entities = PaperweightPlatformAdapter.getEntities(nmsChunk); - - for (Entity entity : entities) { - UUID uuid = entity.getUUID(); - if (entityRemoves.contains(uuid)) { - if (createCopy) { - copy.storeEntity(entity); - } - removeEntity(entity); - entitiesRemoved.add(uuid); - entityRemoves.remove(uuid); - } - } - if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { - for (UUID uuid : entityRemoves) { - Entity entity = nmsWorld.getEntities().get(uuid); - if (entity != null) { - removeEntity(entity); - } - } - } - // Only save entities that were actually removed to history - set.getEntityRemoves().clear(); - set.getEntityRemoves().addAll(entitiesRemoved); - }; - } - - Set entities = set.getEntities(); - if (entities != null && !entities.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[2]; - } - - syncTasks[1] = () -> { - Iterator iterator = entities.iterator(); - while (iterator.hasNext()) { - final CompoundTag nativeTag = iterator.next(); - final Map> entityTagMap = nativeTag.getValue(); - final StringTag idTag = (StringTag) entityTagMap.get("Id"); - final ListTag posTag = (ListTag) entityTagMap.get("Pos"); - final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); - if (idTag == null || posTag == null || rotTag == null) { - LOGGER.error("Unknown entity tag: {}", nativeTag); - continue; - } - final double x = posTag.getDouble(0); - final double y = posTag.getDouble(1); - final double z = posTag.getDouble(2); - final float yaw = rotTag.getFloat(0); - final float pitch = rotTag.getFloat(1); - final String id = idTag.getValue(); - - EntityType type = EntityType.byString(id).orElse(null); - if (type != null) { - Entity entity = type.create(nmsWorld); - if (entity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); - for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - entity.load(tag); - entity.absMoveTo(x, y, z, yaw, pitch); - entity.setUUID(nativeTag.getUUID()); - if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { - LOGGER.warn( - "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", - id, - nmsWorld.getWorld().getName(), - x, - y, - z - ); - // Unsuccessful create should not be saved to history - iterator.remove(); - } - } - } - } - }; - } - - // set tiles - Map tiles = set.getTiles(); - if (tiles != null && !tiles.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[1]; - } - - syncTasks[0] = () -> { - for (final Map.Entry entry : tiles.entrySet()) { - final CompoundTag nativeTag = entry.getValue(); - final BlockVector3 blockHash = entry.getKey(); - final int x = blockHash.x() + bx; - final int y = blockHash.y(); - final int z = blockHash.z() + bz; - final BlockPos pos = new BlockPos(x, y, z); - - synchronized (nmsWorld) { - BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); - if (tileEntity == null || tileEntity.isRemoved()) { - nmsWorld.removeBlockEntity(pos); - tileEntity = nmsWorld.getBlockEntity(pos); - } - if (tileEntity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); - tag.put("x", IntTag.valueOf(x)); - tag.put("y", IntTag.valueOf(y)); - tag.put("z", IntTag.valueOf(z)); - tileEntity.load(tag); - } - } - } - }; - } - - Runnable callback; - if (bitMask == 0 && biomes == null && !lightUpdate) { - callback = null; - } else { - int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; - boolean finalLightUpdate = lightUpdate; - callback = () -> { - // Set Modified - nmsChunk.setLightCorrect(true); // Set Modified - nmsChunk.mustNotSave = false; - nmsChunk.setUnsaved(true); - // send to player - if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING || finalMask == 0 && biomes != null) { - this.send(); - } - if (finalizer != null) { - finalizer.run(); - } - }; - } - if (syncTasks != null) { - QueueHandler queueHandler = Fawe.instance().getQueueHandler(); - Runnable[] finalSyncTasks = syncTasks; - - // Chain the sync tasks and the callback - Callable chain = () -> { - try { - // Run the sync tasks - for (Runnable task : finalSyncTasks) { - if (task != null) { - task.run(); - } - } - if (callback == null) { - if (finalizer != null) { - queueHandler.async(finalizer, null); - } - return null; - } else { - return queueHandler.async(callback, null); - } - } catch (Throwable e) { - e.printStackTrace(); - throw e; - } - }; - //noinspection unchecked - required at compile time - return (T) (Future) queueHandler.sync(chain); - } else { - if (callback == null) { - if (finalizer != null) { - finalizer.run(); - } - } else { - callback.run(); - } - } - } - return null; - } catch (Throwable e) { - e.printStackTrace(); - return null; - } finally { - forceLoadSections = true; - } - } - - private void updateGet( - LevelChunk nmsChunk, - LevelChunkSection[] chunkSections, - LevelChunkSection section, - char[] arr, - int layer - ) { - try { - sectionLock.writeLock().lock(); - if (this.getChunk() != nmsChunk) { - this.levelChunk = nmsChunk; - this.sections = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); - this.reset(); - } - if (this.sections == null) { - this.sections = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); - } - if (this.sections[layer] != section) { - // Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords - this.sections[layer] = new LevelChunkSection[]{section}.clone()[0]; - } - } finally { - sectionLock.writeLock().unlock(); - } - this.blocks[layer] = arr; - } - - private char[] loadPrivately(int layer) { - layer -= getMinSectionPosition(); - if (super.sections[layer] != null) { - synchronized (super.sectionLocks[layer]) { - if (super.sections[layer].isFull() && super.blocks[layer] != null) { - return super.blocks[layer]; - } - } - } - return PaperweightGetBlocks.this.update(layer, null, true); - } - - @Override - public void send() { - synchronized (sendLock) { - PaperweightPlatformAdapter.sendChunk(this, serverLevel, chunkX, chunkZ); - } - } - - /** - * Update a given (nullable) data array to the current data stored in the server's chunk, associated with this - * {@link PaperweightPlatformAdapter} instance. Not synchronised to the {@link PaperweightPlatformAdapter} instance as synchronisation - * is handled where necessary in the method, and should otherwise be handled correctly by this method's caller. - * - * @param layer layer index (0 may denote a negative layer in the world, e.g. at y=-32) - * @param data array to be updated/filled with data or null - * @param aggressive if the cached section array should be re-acquired. - * @return the given array to be filled with data, or a new array if null is given. - */ - @Override - @SuppressWarnings("unchecked") - public char[] update(int layer, char[] data, boolean aggressive) { - LevelChunkSection section = getSections(aggressive)[layer]; - // Section is null, return empty array - if (section == null) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - return data; - } - if (data != null && data.length != 4096) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - } - if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - } - Semaphore lock = PaperweightPlatformAdapter.applyLock(section); - synchronized (lock) { - // Efficiently convert ChunkSection to raw data - try { - lock.acquire(); - - final PalettedContainer blocks = section.getStates(); - final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocks); - final BitStorage bits = (BitStorage) PaperweightPlatformAdapter.fieldStorage.get(dataObject); - - if (bits instanceof ZeroBitStorage) { - Arrays.fill(data, adapter.adaptToChar(blocks.get(0, 0, 0))); // get(int) is only public on paper - return data; - } - - final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get(dataObject); - - final int bitsPerEntry = bits.getBits(); - final long[] blockStates = bits.getRaw(); - - new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).toRaw(data); - - int num_palette; - if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { - num_palette = palette.getSize(); - } else { - // The section's palette is the global block palette. - for (int i = 0; i < 4096; i++) { - char paletteVal = data[i]; - char ordinal = adapter.ibdIDToOrdinal(paletteVal); - data[i] = ordinal; - } - return data; - } - - char[] paletteToOrdinal = FaweCache.INSTANCE.PALETTE_TO_BLOCK_CHAR.get(); - try { - if (num_palette != 1) { - for (int i = 0; i < num_palette; i++) { - char ordinal = ordinal(palette.valueFor(i), adapter); - paletteToOrdinal[i] = ordinal; - } - for (int i = 0; i < 4096; i++) { - char paletteVal = data[i]; - char val = paletteToOrdinal[paletteVal]; - if (val == Character.MAX_VALUE) { - val = ordinal(palette.valueFor(i), adapter); - paletteToOrdinal[i] = val; - } - data[i] = val; - } - } else { - char ordinal = ordinal(palette.valueFor(0), adapter); - Arrays.fill(data, ordinal); - } - } finally { - for (int i = 0; i < num_palette; i++) { - paletteToOrdinal[i] = Character.MAX_VALUE; - } - } - return data; - } catch (IllegalAccessException | InterruptedException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } finally { - lock.release(); - } - } - } - - private char ordinal(BlockState ibd, PaperweightFaweAdapter adapter) { - if (ibd == null) { - return BlockTypesCache.ReservedIDs.AIR; - } else { - return adapter.adaptToChar(ibd); - } - } - - public LevelChunkSection[] getSections(boolean force) { - force &= forceLoadSections; - LevelChunkSection[] tmp = sections; - if (tmp == null || force) { - try { - sectionLock.writeLock().lock(); - tmp = sections; - if (tmp == null || force) { - LevelChunkSection[] chunkSections = getChunk().getSections(); - tmp = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length); - sections = tmp; - } - } finally { - sectionLock.writeLock().unlock(); - } - } - return tmp; - } - - public LevelChunk getChunk() { - LevelChunk levelChunk = this.levelChunk; - if (levelChunk == null) { - synchronized (this) { - levelChunk = this.levelChunk; - if (levelChunk == null) { - this.levelChunk = levelChunk = ensureLoaded(this.serverLevel, chunkX, chunkZ); - } - } - } - return levelChunk; - } - - private void fillLightNibble(char[][] light, LightLayer lightLayer, int minSectionPosition, int maxSectionPosition) { - for (int Y = 0; Y <= maxSectionPosition - minSectionPosition; Y++) { - if (light[Y] == null) { - continue; - } - SectionPos sectionPos = SectionPos.of(levelChunk.getPos(), Y + minSectionPosition); - DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(lightLayer).getDataLayerData( - sectionPos); - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - Arrays.fill(LAYER_COUNT, lightLayer == LightLayer.SKY ? (byte) 15 : (byte) 0); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( - lightLayer, - sectionPos, - dataLayer, - true - ); - } - synchronized (dataLayer) { - for (int x = 0; x < 16; x++) { - for (int y = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { - int i = y << 8 | z << 4 | x; - if (light[Y][i] < 16) { - dataLayer.set(x, y, z, light[Y][i]); - } - } - } - } - } - } - } - - private PalettedContainer> setBiomesToPalettedContainer( - final BiomeType[][] biomes, - final int sectionIndex, - final PalettedContainerRO> data - ) { - BiomeType[] sectionBiomes; - if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { - return null; - } - PalettedContainer> biomeData = data.recreate(); - for (int y = 0, index = 0; y < 4; y++) { - for (int z = 0; z < 4; z++) { - for (int x = 0; x < 4; x++, index++) { - BiomeType biomeType = sectionBiomes[index]; - if (biomeType == null) { - biomeData.set(x, y, z, data.get(x, y, z)); - } else { - biomeData.set( - x, - y, - z, - biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) - ); - } - } - } - } - return biomeData; - } - - @Override - public boolean hasSection(int layer) { - layer -= getMinSectionPosition(); - return getSections(false)[layer] != null; - } - - @Override - @SuppressWarnings("unchecked") - public synchronized boolean trim(boolean aggressive) { - skyLight = new DataLayer[getSectionCount()]; - blockLight = new DataLayer[getSectionCount()]; - if (aggressive) { - sectionLock.writeLock().lock(); - sections = null; - levelChunk = null; - sectionLock.writeLock().unlock(); - return super.trim(true); - } else if (sections == null) { - // don't bother trimming if there are no sections stored. - return true; - } else { - for (int i = getMinSectionPosition(); i <= getMaxSectionPosition(); i++) { - int layer = i - getMinSectionPosition(); - if (!hasSection(i) || !super.sections[layer].isFull()) { - continue; - } - LevelChunkSection existing = getSections(true)[layer]; - try { - final PalettedContainer blocksExisting = existing.getStates(); - - final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocksExisting); - final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get( - dataObject); - int paletteSize; - - if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { - paletteSize = palette.getSize(); - } else { - super.trim(false, i); - continue; - } - if (paletteSize == 1) { - //If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks. - continue; - } - super.trim(false, i); - } catch (IllegalAccessException ignored) { - super.trim(false, i); - } - } - return true; - } - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java deleted file mode 100644 index dd1787868..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java +++ /dev/null @@ -1,259 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; - -import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; -import com.fastasyncworldedit.core.queue.IBlocks; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.math.BlockVector3; -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.BlockTypesCache; -import net.minecraft.core.Holder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import org.apache.logging.log4j.Logger; - -import javax.annotation.Nullable; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Future; - -public class PaperweightGetBlocks_Copy implements IChunkGet { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private final Map tiles = new HashMap<>(); - private final Set entities = new HashSet<>(); - private final char[][] blocks; - private final int minHeight; - private final int maxHeight; - final ServerLevel serverLevel; - final LevelChunk levelChunk; - private Holder[][] biomes = null; - - protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { - this.levelChunk = levelChunk; - this.serverLevel = levelChunk.level; - this.minHeight = serverLevel.getMinBuildHeight(); - this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. - this.blocks = new char[getSectionCount()][]; - } - - protected void storeTile(BlockEntity blockEntity) { - tiles.put( - BlockVector3.at( - blockEntity.getBlockPos().getX(), - blockEntity.getBlockPos().getY(), - blockEntity.getBlockPos().getZ() - ), - new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)) - ); - } - - @Override - public Map getTiles() { - return tiles; - } - - @Override - @Nullable - public CompoundTag getTile(int x, int y, int z) { - return tiles.get(BlockVector3.at(x, y, z)); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - protected void storeEntity(Entity entity) { - BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(entity, compoundTag); - entities.add((CompoundTag) adapter.toNative(compoundTag)); - } - - @Override - public Set getEntities() { - return this.entities; - } - - @Override - public CompoundTag getEntity(UUID uuid) { - for (CompoundTag tag : entities) { - if (uuid.equals(tag.getUUID())) { - return tag; - } - } - return null; - } - - @Override - public boolean isCreateCopy() { - return false; - } - - @Override - public int setCreateCopy(boolean createCopy) { - return -1; - } - - @Override - public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { - } - - @Override - public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { - } - - @Override - public void setHeightmapToGet(HeightMapType type, int[] data) { - } - - @Override - public int getMaxY() { - return maxHeight; - } - - @Override - public int getMinY() { - return minHeight; - } - - @Override - public int getMaxSectionPosition() { - return maxHeight >> 4; - } - - @Override - public int getMinSectionPosition() { - return minHeight >> 4; - } - - @Override - public BiomeType getBiomeType(int x, int y, int z) { - Holder biome = biomes[(y >> 4) - getMinSectionPosition()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2]; - return PaperweightPlatformAdapter.adapt(biome, serverLevel); - } - - @Override - public void removeSectionLighting(int layer, boolean sky) { - } - - @Override - public boolean trim(boolean aggressive, int layer) { - return false; - } - - @Override - public IBlocks reset() { - return null; - } - - @Override - public int getSectionCount() { - return serverLevel.getSectionsCount(); - } - - protected void storeSection(int layer, char[] data) { - blocks[layer] = data; - } - - protected void storeBiomes(int layer, PalettedContainerRO> biomeData) { - if (biomes == null) { - biomes = new Holder[getSectionCount()][]; - } - if (biomes[layer] == null) { - biomes[layer] = new Holder[64]; - } - if (biomeData instanceof PalettedContainer> palettedContainer) { - for (int i = 0; i < 64; i++) { - biomes[layer][i] = palettedContainer.get(i); - } - } else { - LOGGER.error( - "Cannot correctly save biomes to history. Expected class type {} but got {}", - PalettedContainer.class.getSimpleName(), - biomeData.getClass().getSimpleName() - ); - } - } - - @Override - public BaseBlock getFullBlock(int x, int y, int z) { - BlockState state = BlockTypesCache.states[get(x, y, z)]; - return state.toBaseBlock(this, x, y, z); - } - - @Override - public boolean hasSection(int layer) { - layer -= getMinSectionPosition(); - return blocks[layer] != null; - } - - @Override - public char[] load(int layer) { - layer -= getMinSectionPosition(); - if (blocks[layer] == null) { - blocks[layer] = new char[4096]; - Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR); - } - return blocks[layer]; - } - - @Override - public char[] loadIfPresent(int layer) { - layer -= getMinSectionPosition(); - return blocks[layer]; - } - - @Override - public BlockState getBlock(int x, int y, int z) { - return BlockTypesCache.states[get(x, y, z)]; - } - - @Override - public int getSkyLight(int x, int y, int z) { - return 0; - } - - @Override - public int getEmittedLight(int x, int y, int z) { - return 0; - } - - @Override - public int[] getHeightMap(HeightMapType type) { - return new int[0]; - } - - @Override - public > T call(IChunkSet set, Runnable finalize) { - return null; - } - - public char get(int x, int y, int z) { - final int layer = (y >> 4) - getMinSectionPosition(); - final int index = (y & 15) << 8 | z << 4 | x; - return blocks[layer][index]; - } - - - @Override - public boolean trim(boolean aggressive) { - return false; - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightMapChunkUtil.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightMapChunkUtil.java deleted file mode 100644 index 7c7f39d9a..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightMapChunkUtil.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; - -import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; - -//TODO un-very-break-this -public class PaperweightMapChunkUtil extends MapChunkUtil { - - public PaperweightMapChunkUtil() throws NoSuchFieldException { - fieldX = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("TWO_MEGABYTES", "a")); - fieldZ = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("x", "a")); - fieldBitMask = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("z", "b")); - fieldHeightMap = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("heightmaps", "b")); - fieldChunkData = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("chunkData", "c")); - fieldBlockEntities = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("buffer", "c")); - fieldFull = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("blockEntitiesData", "d")); - fieldX.setAccessible(true); - fieldZ.setAccessible(true); - fieldBitMask.setAccessible(true); - fieldHeightMap.setAccessible(true); - fieldChunkData.setAccessible(true); - fieldBlockEntities.setAccessible(true); - fieldFull.setAccessible(true); - } - - @Override - public ClientboundLevelChunkWithLightPacket createPacket() { - // TODO ??? return new ClientboundLevelChunkPacket(); - throw new UnsupportedOperationException(); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java deleted file mode 100644 index aec3cfd24..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java +++ /dev/null @@ -1,748 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; - -import com.destroystokyo.paper.util.maplist.EntityList; -import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; -import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; -import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.math.BitArrayUnstretched; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.ReflectionUtils; -import com.fastasyncworldedit.core.util.TaskManager; -import com.mojang.datafixers.util.Either; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -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.BlockTypesCache; -import io.papermc.lib.PaperLib; -import io.papermc.paper.world.ChunkEntitySlices; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.IdMap; -import net.minecraft.core.Registry; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.level.TicketType; -import net.minecraft.util.BitStorage; -import net.minecraft.util.ExceptionCollector; -import net.minecraft.util.SimpleBitStorage; -import net.minecraft.util.ThreadingDetector; -import net.minecraft.util.Unit; -import net.minecraft.util.ZeroBitStorage; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.npc.AbstractVillager; -import net.minecraft.world.item.trading.MerchantOffers; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.GlobalPalette; -import net.minecraft.world.level.chunk.HashMapPalette; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.LinearPalette; -import net.minecraft.world.level.chunk.Palette; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.SingleValuePalette; -import net.minecraft.world.level.entity.PersistentEntitySectionManager; -import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_19_R3.CraftChunk; -import sun.misc.Unsafe; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.function.Function; - -import static net.minecraft.core.registries.Registries.BIOME; - -public final class PaperweightPlatformAdapter extends NMSAdapter { - - public static final Field fieldData; - - public static final Constructor dataConstructor; - - public static final Field fieldStorage; - public static final Field fieldPalette; - - private static final Field fieldTickingFluidCount; - private static final Field fieldTickingBlockCount; - private static final Field fieldBiomes; - - private static final MethodHandle methodGetVisibleChunk; - - private static final Field fieldThreadingDetector; - private static final Field fieldLock; - - private static final MethodHandle methodRemoveGameEventListener; - private static final MethodHandle methodremoveTickingBlockEntity; - - private static final Field fieldOffers; - private static final MerchantOffers OFFERS = new MerchantOffers(); - - private static final Field fieldRemove; - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - static final boolean POST_CHUNK_REWRITE; - private static Method PAPER_CHUNK_GEN_ALL_ENTITIES; - private static Field LEVEL_CHUNK_ENTITIES; - private static Field SERVER_LEVEL_ENTITY_MANAGER; - - static { - final MethodHandles.Lookup lookup = MethodHandles.lookup(); - try { - fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d")); - fieldData.setAccessible(true); - - Class dataClazz = fieldData.getType(); - dataConstructor = dataClazz.getDeclaredConstructors()[0]; - dataConstructor.setAccessible(true); - - fieldStorage = dataClazz.getDeclaredField(Refraction.pickName("storage", "b")); - fieldStorage.setAccessible(true); - fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c")); - fieldPalette.setAccessible(true); - - fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "h")); - fieldTickingFluidCount.setAccessible(true); - fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g")); - fieldTickingBlockCount.setAccessible(true); - Field tmpFieldBiomes; - try { - // It seems to actually be biomes, but is apparently obfuscated to "j" - tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); - } catch (NoSuchFieldException ignored) { - tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("j"); - } - fieldBiomes = tmpFieldBiomes; - fieldBiomes.setAccessible(true); - - Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( - "getVisibleChunkIfPresent", - "b" - ), long.class); - getVisibleChunkIfPresent.setAccessible(true); - methodGetVisibleChunk = lookup.unreflect(getVisibleChunkIfPresent); - - if (!PaperLib.isPaper()) { - fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); - fieldThreadingDetector.setAccessible(true); - fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); - fieldLock.setAccessible(true); - } else { - // in paper, the used methods are synchronized properly - fieldThreadingDetector = null; - fieldLock = null; - } - - Method removeGameEventListener = LevelChunk.class.getDeclaredMethod( - Refraction.pickName("removeGameEventListener", "a"), - BlockEntity.class, - ServerLevel.class - ); - removeGameEventListener.setAccessible(true); - methodRemoveGameEventListener = lookup.unreflect(removeGameEventListener); - - Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod( - Refraction.pickName( - "removeBlockEntityTicker", - "l" - ), BlockPos.class - ); - removeBlockEntityTicker.setAccessible(true); - methodremoveTickingBlockEntity = lookup.unreflect(removeBlockEntityTicker); - - fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "q")); - fieldRemove.setAccessible(true); - - boolean chunkRewrite; - try { - ServerLevel.class.getDeclaredMethod("getEntityLookup"); - chunkRewrite = true; - PAPER_CHUNK_GEN_ALL_ENTITIES = ChunkEntitySlices.class.getDeclaredMethod("getAllEntities"); - PAPER_CHUNK_GEN_ALL_ENTITIES.setAccessible(true); - } catch (NoSuchMethodException ignored) { - chunkRewrite = false; - } - try { - // Paper - Pre-Chunk-Update - LEVEL_CHUNK_ENTITIES = LevelChunk.class.getDeclaredField("entities"); - LEVEL_CHUNK_ENTITIES.setAccessible(true); - } catch (NoSuchFieldException ignored) { - } - try { - // Non-Paper - SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "L")); - SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true); - } catch (NoSuchFieldException ignored) { - } - POST_CHUNK_REWRITE = chunkRewrite; - - fieldOffers = AbstractVillager.class.getDeclaredField(Refraction.pickName("offers", "bT")); - fieldOffers.setAccessible(true); - } catch (RuntimeException | Error e) { - throw e; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - static boolean setSectionAtomic( - LevelChunkSection[] sections, - LevelChunkSection expected, - LevelChunkSection value, - int layer - ) { - if (layer >= 0 && layer < sections.length) { - return ReflectionUtils.compareAndSet(sections, expected, value, layer); - } - return false; - } - - // There is no point in having a functional semaphore for paper servers. - private static final ThreadLocal SEMAPHORE_THREAD_LOCAL = - ThreadLocal.withInitial(() -> new DelegateSemaphore(1, null)); - - static DelegateSemaphore applyLock(LevelChunkSection section) { - if (PaperLib.isPaper()) { - return SEMAPHORE_THREAD_LOCAL.get(); - } - try { - synchronized (section) { - PalettedContainer blocks = section.getStates(); - ThreadingDetector currentThreadingDetector = (ThreadingDetector) fieldThreadingDetector.get(blocks); - synchronized (currentThreadingDetector) { - Semaphore currentLock = (Semaphore) fieldLock.get(currentThreadingDetector); - if (currentLock instanceof DelegateSemaphore delegateSemaphore) { - return delegateSemaphore; - } - DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); - fieldLock.set(currentThreadingDetector, newLock); - return newLock; - } - } - } catch (Throwable e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - } - - public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) { - if (!PaperLib.isPaper()) { - LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false); - if (nmsChunk != null) { - return nmsChunk; - } - if (Fawe.isMainThread()) { - return serverLevel.getChunk(chunkX, chunkZ); - } - } else { - LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ); - if (nmsChunk != null) { - addTicket(serverLevel, chunkX, chunkZ); - return nmsChunk; - } - nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ); - if (nmsChunk != null) { - addTicket(serverLevel, chunkX, chunkZ); - return nmsChunk; - } - // Avoid "async" methods from the main thread. - if (Fawe.isMainThread()) { - return serverLevel.getChunk(chunkX, chunkZ); - } - CompletableFuture future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true); - try { - CraftChunk chunk; - try { - chunk = (CraftChunk) future.get(10, TimeUnit.SECONDS); - } catch (TimeoutException e) { - String world = serverLevel.getWorld().getName(); - // We've already taken 10 seconds we can afford to wait a little here. - boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null); - if (loaded) { - LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world); - // Retry chunk load - chunk = (CraftChunk) serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true).get(); - } else { - throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!"); - } - } - addTicket(serverLevel, chunkX, chunkZ); - return (LevelChunk) chunk.getHandle(ChunkStatus.FULL); - } catch (Throwable e) { - e.printStackTrace(); - } - } - return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)); - } - - private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) { - // Ensure chunk is definitely loaded before applying a ticket - io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel - .getChunkSource() - .addRegionTicket(TicketType.UNLOAD_COOLDOWN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE)); - } - - public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) { - ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap; - try { - return (ChunkHolder) methodGetVisibleChunk.invoke(chunkMap, ChunkPos.asLong(chunkX, chunkZ)); - } catch (Throwable thr) { - throw new RuntimeException(thr); - } - } - - @SuppressWarnings("deprecation") - public static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int chunkZ) { - ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); - if (chunkHolder == null) { - return; - } - ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ); - LevelChunk levelChunk; - if (PaperLib.isPaper()) { - // getChunkAtIfLoadedImmediately is paper only - levelChunk = nmsWorld - .getChunkSource() - .getChunkAtIfLoadedImmediately(chunkX, chunkZ); - } else { - levelChunk = ((Optional) ((Either) chunkHolder - .getTickingChunkFuture() // method is not present with new paper chunk system - .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left()) - .orElse(null); - } - if (levelChunk == null) { - return; - } - MinecraftServer.getServer().execute(() -> { - ClientboundLevelChunkWithLightPacket packet; - if (PaperLib.isPaper()) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - true, - false // last false is to not bother with x-ray - ); - } else { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - true - ); - } - nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); - }); - } - - private static List nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) { - return serverLevel.getChunkSource().chunkMap.getPlayers(coordIntPair, false); - } - - /* - NMS conversion - */ - public static LevelChunkSection newChunkSection( - final int layer, - final char[] blocks, - CachedBukkitAdapter adapter, - Registry biomeRegistry, - @Nullable PalettedContainer> biomes - ) { - return newChunkSection(layer, null, blocks, adapter, biomeRegistry, biomes); - } - - public static LevelChunkSection newChunkSection( - final int layer, - final Function get, - char[] set, - CachedBukkitAdapter adapter, - Registry biomeRegistry, - @Nullable PalettedContainer> biomes - ) { - if (set == null) { - return newChunkSection(layer, biomeRegistry, biomes); - } - final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); - final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); - final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get(); - final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get(); - try { - int num_palette; - if (get == null) { - num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter, null); - } else { - num_palette = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, get, set, adapter, null); - } - - int bitsPerEntry = MathMan.log2nlz(num_palette - 1); - if (bitsPerEntry > 0 && bitsPerEntry < 5) { - bitsPerEntry = 4; - } else if (bitsPerEntry > 8) { - bitsPerEntry = MathMan.log2nlz(Block.BLOCK_STATE_REGISTRY.size() - 1); - } - - int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes - final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); - final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong); - - if (num_palette == 1) { - for (int i = 0; i < blockBitArrayEnd; i++) { - blockStates[i] = 0; - } - } else { - final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntryNonZero, 4096, blockStates); - bitArray.fromRaw(blocksCopy); - } - - final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd); - final BitStorage nmsBits; - if (bitsPerEntry == 0) { - nmsBits = new ZeroBitStorage(4096); - } else { - nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits); - } - List palette; - if (bitsPerEntry < 9) { - palette = new ArrayList<>(); - for (int i = 0; i < num_palette; i++) { - int ordinal = paletteToBlock[i]; - blockToPalette[ordinal] = Integer.MAX_VALUE; - final BlockState state = BlockTypesCache.states[ordinal]; - palette.add(((PaperweightBlockMaterial) state.getMaterial()).getState()); - } - } else { - palette = List.of(); - } - - // Create palette with data - @SuppressWarnings("deprecation") // constructor is deprecated on paper, but needed to keep compatibility with spigot - final PalettedContainer blockStatePalettedContainer = - new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, - PalettedContainer.Strategy.SECTION_STATES, - PalettedContainer.Strategy.SECTION_STATES.getConfiguration(Block.BLOCK_STATE_REGISTRY, bitsPerEntry), - nmsBits, - palette - ); - if (biomes == null) { - IdMap> biomeHolderIdMap = biomeRegistry.asHolderIdMap(); - biomes = new PalettedContainer<>( - biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId( - BiomeTypes.PLAINS)), - PalettedContainer.Strategy.SECTION_BIOMES, - null - ); - } - - return new LevelChunkSection(layer, blockStatePalettedContainer, biomes); - } catch (final Throwable e) { - throw e; - } finally { - Arrays.fill(blockToPalette, Integer.MAX_VALUE); - Arrays.fill(paletteToBlock, Integer.MAX_VALUE); - Arrays.fill(blockStates, 0); - Arrays.fill(blocksCopy, 0); - } - } - - @SuppressWarnings("deprecation") // Only deprecated in paper - private static LevelChunkSection newChunkSection( - int layer, - Registry biomeRegistry, - @Nullable PalettedContainer> biomes - ) { - if (biomes == null) { - return new LevelChunkSection(layer, biomeRegistry); - } - PalettedContainer dataPaletteBlocks = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, - Blocks.AIR.defaultBlockState(), - PalettedContainer.Strategy.SECTION_STATES, - null - ); - return new LevelChunkSection(layer, dataPaletteBlocks, biomes); - } - - public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer> biomes) { - try { - fieldBiomes.set(section, biomes); - } catch (IllegalAccessException e) { - LOGGER.error("Could not set biomes to chunk section", e); - } - } - - /** - * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. - */ - public static PalettedContainer> getBiomePalettedContainer( - BiomeType[] biomes, - IdMap> biomeRegistry - ) { - if (biomes == null) { - return null; - } - BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); - // Don't stream this as typically will see 1-4 biomes; stream overhead is large for the small length - Map> palette = new HashMap<>(); - for (BiomeType biomeType : new LinkedList<>(Arrays.asList(biomes))) { - Holder biome; - if (biomeType == null) { - biome = biomeRegistry.byId(adapter.getInternalBiomeId(BiomeTypes.PLAINS)); - } else { - biome = biomeRegistry.byId(adapter.getInternalBiomeId(biomeType)); - } - palette.put(biomeType, biome); - } - int biomeCount = palette.size(); - int bitsPerEntry = MathMan.log2nlz(biomeCount - 1); - Object configuration = PalettedContainer.Strategy.SECTION_STATES.getConfiguration( - new FakeIdMapBiome(biomeCount), - bitsPerEntry - ); - if (bitsPerEntry > 3) { - bitsPerEntry = MathMan.log2nlz(biomeRegistry.size() - 1); - } - PalettedContainer> biomePalettedContainer = new PalettedContainer<>( - biomeRegistry, - biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), - PalettedContainer.Strategy.SECTION_BIOMES, - null - ); - - final Palette> biomePalette; - if (bitsPerEntry == 0) { - biomePalette = new SingleValuePalette<>( - biomePalettedContainer.registry, - biomePalettedContainer, - new ArrayList<>(palette.values()) // Must be modifiable - ); - } else if (bitsPerEntry == 4) { - biomePalette = LinearPalette.create( - 4, - biomePalettedContainer.registry, - biomePalettedContainer, - new ArrayList<>(palette.values()) // Must be modifiable - ); - } else if (bitsPerEntry < 9) { - biomePalette = HashMapPalette.create( - bitsPerEntry, - biomePalettedContainer.registry, - biomePalettedContainer, - new ArrayList<>(palette.values()) // Must be modifiable - ); - } else { - biomePalette = GlobalPalette.create( - bitsPerEntry, - biomePalettedContainer.registry, - biomePalettedContainer, - null // unused - ); - } - - int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes - final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); - final int arrayLength = MathMan.ceilZero(64f / blocksPerLong); - - - BitStorage bitStorage = bitsPerEntry == 0 ? new ZeroBitStorage(64) : new SimpleBitStorage( - bitsPerEntry, - 64, - new long[arrayLength] - ); - - try { - Object data = dataConstructor.newInstance(configuration, bitStorage, biomePalette); - fieldData.set(biomePalettedContainer, data); - int index = 0; - for (int y = 0; y < 4; y++) { - for (int z = 0; z < 4; z++) { - for (int x = 0; x < 4; x++, index++) { - BiomeType biomeType = biomes[index]; - if (biomeType == null) { - continue; - } - Holder biome = biomeRegistry.byId(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId(biomeType)); - if (biome == null) { - continue; - } - biomePalettedContainer.set(x, y, z, biome); - } - } - } - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException(e); - } - return biomePalettedContainer; - } - - public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException { - fieldTickingFluidCount.setShort(section, (short) 0); - fieldTickingBlockCount.setShort(section, (short) 0); - } - - public static BiomeType adapt(Holder biome, LevelAccessor levelAccessor) { - final Registry biomeRegistry = levelAccessor.registryAccess().registryOrThrow(BIOME); - if (biomeRegistry.getKey(biome.value()) == null) { - return biomeRegistry.asHolderIdMap().getId(biome) == -1 ? BiomeTypes.OCEAN - : null; - } - return BiomeTypes.get(biome.unwrapKey().orElseThrow().location().toString()); - } - - static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { - try { - if (levelChunk.loaded || levelChunk.level.isClientSide()) { - BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos()); - if (blockEntity != null) { - if (!levelChunk.level.isClientSide) { - methodRemoveGameEventListener.invoke(levelChunk, beacon, levelChunk.level); - } - fieldRemove.set(beacon, true); - } - } - methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos()); - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - } - - static List getEntities(LevelChunk chunk) { - ExceptionCollector collector = new ExceptionCollector<>(); - if (PaperLib.isPaper()) { - if (POST_CHUNK_REWRITE) { - try { - //noinspection unchecked - return (List) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level.getEntityLookup().getChunk(chunk.locX, chunk.locZ)); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=true]", e); - } - } - try { - EntityList entityList = (EntityList) LEVEL_CHUNK_ENTITIES.get(chunk); - return List.of(entityList.getRawData()); - } catch (IllegalAccessException e) { - collector.add(new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=false]", e)); - // fall through - } - } - try { - //noinspection unchecked - return ((PersistentEntitySectionManager) (SERVER_LEVEL_ENTITY_MANAGER.get(chunk.level))).getEntities(chunk.getPos()); - } catch (IllegalAccessException e) { - collector.add(new RuntimeException("Failed to lookup entities [PAPER=false]", e)); - } - collector.throwIfPresent(); - return List.of(); - } - - public static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { - boolean isVillager = entity instanceof AbstractVillager && !Fawe.isMainThread(); - boolean unset = false; - if (isVillager) { - try { - if (fieldOffers.get(entity) != null) { - fieldOffers.set(entity, OFFERS); - unset = true; - } - } catch (IllegalAccessException e) { - throw new RuntimeException("Failed to set offers field to villager to avoid async catcher.", e); - } - } - entity.save(compoundTag); - if (unset) { - try { - fieldOffers.set(entity, null); - } catch (IllegalAccessException e) { - throw new RuntimeException("Failed to set offers field to null again on villager.", e); - } - } - } - - record FakeIdMapBlock(int size) implements IdMap { - - @Override - public int getId(final net.minecraft.world.level.block.state.BlockState entry) { - return 0; - } - - @Nullable - @Override - public net.minecraft.world.level.block.state.BlockState byId(final int index) { - return null; - } - - @Nonnull - @Override - public Iterator iterator() { - return Collections.emptyIterator(); - } - - } - - record FakeIdMapBiome(int size) implements IdMap { - - @Override - public int getId(final Biome entry) { - return 0; - } - - @Nullable - @Override - public Biome byId(final int index) { - return null; - } - - @Nonnull - @Override - public Iterator iterator() { - return Collections.emptyIterator(); - } - - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPostProcessor.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPostProcessor.java deleted file mode 100644 index ac10f2c0a..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPostProcessor.java +++ /dev/null @@ -1,175 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; - -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.ProcessorScope; -import com.fastasyncworldedit.core.queue.IBatchProcessor; -import com.fastasyncworldedit.core.queue.IChunk; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.fastasyncworldedit.core.registry.state.PropertyKey; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.Fluids; - -import javax.annotation.Nullable; - -public class PaperweightPostProcessor implements IBatchProcessor { - - @Override - public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) { - return set; - } - - @SuppressWarnings("deprecation") - @Override - public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) { - boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS; - // The PostProcessor shouldn't be added, but just in case - if (!tickFluid) { - return; - } - PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet; - layer: - for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) { - char[] set = iChunkSet.loadIfPresent(layer); - if (set == null) { - // No edit means no need to process - continue; - } - char[] get = null; - for (int i = 0; i < 4096; i++) { - char ordinal = set[i]; - char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__; - boolean fromGet = false; // Used for liquids - if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { - if (get == null) { - get = getBlocks.load(layer); - } - // If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't - // actually being set - if (get == null) { - continue layer; - } - fromGet = true; - ordinal = replacedOrdinal = get[i]; - } - if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { - continue; - } else if (!fromGet) { // if fromGet, don't do the same again - if (get == null) { - get = getBlocks.load(layer); - } - replacedOrdinal = get[i]; - } - boolean ticking = BlockTypesCache.ticking[ordinal]; - boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal]; - boolean replacedWasLiquid = false; - BlockState replacedState = null; - if (!ticking) { - // If the block being replaced was not ticking, it cannot be a liquid - if (!replacedWasTicking) { - continue; - } - // If the block being replaced is not fluid, we do not need to worry - if (!(replacedWasLiquid = - (replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) { - continue; - } - } - BlockState state = BlockState.getFromOrdinal(ordinal); - boolean liquid = state.getMaterial().isLiquid(); - int x = i & 15; - int y = (i >> 8) & 15; - int z = (i >> 4) & 15; - BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z); - if (liquid || replacedWasLiquid) { - if (liquid) { - addFluid(getBlocks.serverLevel, state, position); - continue; - } - // If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this - // may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up - // being ticked anyway. We only need it to be "hit" once. - if (!wasAdjacentToWater(get, set, i, x, y, z)) { - continue; - } - addFluid(getBlocks.serverLevel, replacedState, position); - } - } - } - } - - @Nullable - @Override - public Extent construct(final Extent child) { - throw new UnsupportedOperationException("Processing only"); - } - - @Override - public ProcessorScope getScope() { - return ProcessorScope.READING_SET_BLOCKS; - } - - private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) { - if (set == null || get == null) { - return false; - } - char ordinal; - char reserved = BlockTypesCache.ReservedIDs.__RESERVED__; - if (x > 0 && set[i - 1] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) { - return true; - } - } - if (x < 15 && set[i + 1] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) { - return true; - } - } - if (z > 0 && set[i - 16] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) { - return true; - } - } - if (z < 15 && set[i + 16] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) { - return true; - } - } - if (y > 0 && set[i - 256] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) { - return true; - } - } - if (y < 15 && set[i + 256] != reserved) { - return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal); - } - return false; - } - - @SuppressWarnings("deprecation") - private boolean isFluid(char ordinal) { - return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid(); - } - - @SuppressWarnings("deprecation") - private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) { - Fluid type; - if (replacedState.getBlockType() == BlockTypes.LAVA) { - type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA; - } else { - type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER; - } - serverLevel.scheduleTick( - position, - type, - type.getTickDelay(serverLevel) - ); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java deleted file mode 100644 index b1e0c5772..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; - -import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.queue.IQueueExtent; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.TicketType; -import net.minecraft.util.Unit; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.chunk.ChunkStatus; - -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; -import java.util.function.IntConsumer; - -public class PaperweightStarlightRelighter extends StarlightRelighter { - - private static final TicketType FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); - private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkStatus.getDistance(ChunkStatus.LIGHT); - - public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { - super(serverLevel, queue); - } - - @Override - protected ChunkPos createChunkPos(final long chunkKey) { - return new ChunkPos(chunkKey); - } - - @Override - protected long asLong(final int chunkX, final int chunkZ) { - return ChunkPos.asLong(chunkX, chunkZ); - } - - @Override - protected CompletableFuture chunkLoadFuture(final ChunkPos chunkPos) { - return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z) - .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( - FAWE_TICKET, - chunkPos, - LIGHT_LEVEL, - Unit.INSTANCE - )); - } - - protected void invokeRelight( - Set coords, - Consumer chunkCallback, - IntConsumer processCallback - ) { - try { - serverLevel.getChunkSource().getLightEngine().relight(coords, chunkCallback, processCallback); - } catch (Exception e) { - LOGGER.error("Error occurred on relighting", e); - } - } - - /* - * Allow the server to unload the chunks again. - * Also, if chunk packets are sent delayed, we need to do that here - */ - protected void postProcessChunks(Set coords) { - boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING; - for (ChunkPos pos : coords) { - int x = pos.x; - int z = pos.z; - if (delay) { // we still need to send the block changes of that chunk - PaperweightPlatformAdapter.sendChunk(pos, serverLevel, x, z); - } - serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE); - } - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighterFactory.java deleted file mode 100644 index 78c623c7a..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighterFactory.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; - -import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; -import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; -import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; -import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IQueueExtent; -import com.sk89q.worldedit.world.World; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; - -import javax.annotation.Nonnull; - -public class PaperweightStarlightRelighterFactory implements RelighterFactory { - - @Override - public @Nonnull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { - org.bukkit.World w = Bukkit.getWorld(world.getName()); - if (w == null) { - return NullRelighter.INSTANCE; - } - return new PaperweightStarlightRelighter(((CraftWorld) w).getHandle(), queue); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/nbt/PaperweightLazyCompoundTag.java deleted file mode 100644 index 0026c4c67..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/nbt/PaperweightLazyCompoundTag.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.LazyCompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import net.minecraft.nbt.NumericTag; -import org.enginehub.linbus.tree.LinCompoundTag; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Supplier; - -public class PaperweightLazyCompoundTag extends LazyCompoundTag { - - private final Supplier compoundTagSupplier; - private CompoundTag compoundTag; - - public PaperweightLazyCompoundTag(Supplier compoundTagSupplier) { - super(new HashMap<>()); - this.compoundTagSupplier = compoundTagSupplier; - } - - public PaperweightLazyCompoundTag(net.minecraft.nbt.CompoundTag compoundTag) { - this(() -> compoundTag); - } - - public net.minecraft.nbt.CompoundTag get() { - return compoundTagSupplier.get(); - } - - @Override - @SuppressWarnings("unchecked") - public Map> getValue() { - if (compoundTag == null) { - compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); - } - return compoundTag.getValue(); - } - - @Override - public LinCompoundTag toLinTag() { - getValue(); - return compoundTag.toLinTag(); - } - - public boolean containsKey(String key) { - return compoundTagSupplier.get().contains(key); - } - - public byte[] getByteArray(String key) { - return compoundTagSupplier.get().getByteArray(key); - } - - public byte getByte(String key) { - return compoundTagSupplier.get().getByte(key); - } - - public double getDouble(String key) { - return compoundTagSupplier.get().getDouble(key); - } - - public double asDouble(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsDouble(); - } - return 0; - } - - public float getFloat(String key) { - return compoundTagSupplier.get().getFloat(key); - } - - public int[] getIntArray(String key) { - return compoundTagSupplier.get().getIntArray(key); - } - - public int getInt(String key) { - return compoundTagSupplier.get().getInt(key); - } - - public int asInt(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsInt(); - } - return 0; - } - - @SuppressWarnings("unchecked") - public List> getList(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof net.minecraft.nbt.ListTag nbtList) { - ArrayList> list = new ArrayList<>(); - for (net.minecraft.nbt.Tag elem : nbtList) { - if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { - list.add(new PaperweightLazyCompoundTag(compoundTag)); - } else { - list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem)); - } - } - return list; - } - return Collections.emptyList(); - } - - @SuppressWarnings("unchecked") - public ListTag getListTag(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof net.minecraft.nbt.ListTag) { - return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag); - } - return new ListTag(StringTag.class, Collections.emptyList()); - } - - @SuppressWarnings("unchecked") - public > List getList(String key, Class listType) { - ListTag listTag = getListTag(key); - if (listTag.getType().equals(listType)) { - return (List) listTag.getValue(); - } else { - return Collections.emptyList(); - } - } - - public long[] getLongArray(String key) { - return compoundTagSupplier.get().getLongArray(key); - } - - public long getLong(String key) { - return compoundTagSupplier.get().getLong(key); - } - - public long asLong(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsLong(); - } - return 0; - } - - public short getShort(String key) { - return compoundTagSupplier.get().getShort(key); - } - - public String getString(String key) { - return compoundTagSupplier.get().getString(key); - } - - @Override - public String toString() { - return compoundTagSupplier.get().toString(); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java deleted file mode 100644 index 17b354535..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java +++ /dev/null @@ -1,596 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.regen; - -import com.fastasyncworldedit.bukkit.adapter.Regenerator; -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.queue.IChunkCache; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.util.ReflectionUtils; -import com.fastasyncworldedit.core.util.TaskManager; -import com.google.common.collect.ImmutableList; -import com.mojang.datafixers.util.Either; -import com.mojang.serialization.Lifecycle; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.PaperweightGetBlocks; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.world.RegenOptions; -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.server.level.progress.ChunkProgressListener; -import net.minecraft.util.thread.ProcessorHandle; -import net.minecraft.util.thread.ProcessorMailbox; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.LevelSettings; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.BiomeSource; -import net.minecraft.world.level.biome.FixedBiomeSource; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkGenerator; -import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.FlatLevelSource; -import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; -import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; -import net.minecraft.world.level.levelgen.WorldOptions; -import net.minecraft.world.level.levelgen.blending.BlendingData; -import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; -import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; -import net.minecraft.world.level.storage.LevelStorageSource; -import net.minecraft.world.level.storage.PrimaryLevelData; -import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.craftbukkit.v1_19_R3.CraftServer; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.generator.CustomChunkGenerator; -import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; - -import javax.annotation.Nullable; -import java.lang.reflect.Field; -import java.nio.file.Path; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.OptionalLong; -import java.util.Random; -import java.util.concurrent.CompletableFuture; -import java.util.function.BooleanSupplier; -import java.util.function.Supplier; - -import static net.minecraft.core.registries.Registries.BIOME; - -public class PaperweightRegen extends Regenerator { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private static final Field serverWorldsField; - private static final Field paperConfigField; - private static final Field flatBedrockField; - private static final Field generatorSettingFlatField; - private static final Field generatorSettingBaseSupplierField; - private static final Field delegateField; - private static final Field chunkSourceField; - private static final Field generatorStructureStateField; - private static final Field ringPositionsField; - private static final Field hasGeneratedPositionsField; - - //list of chunk stati in correct order without FULL - private static final Map chunkStati = new LinkedHashMap<>(); - - static { - chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing - chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps - chunkStati.put( - ChunkStatus.STRUCTURE_REFERENCES, - Concurrency.FULL - ); // structure refs: radius 8, but only writes to current chunk - chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // biomes: radius 0 - chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8 - chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE - chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results - chunkStati.put( - ChunkStatus.LIQUID_CARVERS, - Concurrency.NONE - ); // liquid carvers: radius 0, but RADIUS and FULL change results - chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps - chunkStati.put( - ChunkStatus.LIGHT, - Concurrency.FULL - ); // light: radius 1, but no writes to other chunks, only current chunk - chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0 - chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0 - - try { - serverWorldsField = CraftServer.class.getDeclaredField("worlds"); - serverWorldsField.setAccessible(true); - - Field tmpPaperConfigField; - Field tmpFlatBedrockField; - try { //only present on paper - tmpPaperConfigField = Level.class.getDeclaredField("paperConfig"); - tmpPaperConfigField.setAccessible(true); - - tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock"); - tmpFlatBedrockField.setAccessible(true); - } catch (Exception e) { - tmpPaperConfigField = null; - tmpFlatBedrockField = null; - } - paperConfigField = tmpPaperConfigField; - flatBedrockField = tmpFlatBedrockField; - - generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName( - "settings", "e")); - generatorSettingBaseSupplierField.setAccessible(true); - - generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "d")); - generatorSettingFlatField.setAccessible(true); - - delegateField = CustomChunkGenerator.class.getDeclaredField("delegate"); - delegateField.setAccessible(true); - - chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "H")); - chunkSourceField.setAccessible(true); - - generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "w")); - generatorStructureStateField.setAccessible(true); - - ringPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(Refraction.pickName("ringPositions", "g")); - ringPositionsField.setAccessible(true); - - hasGeneratedPositionsField = ChunkGeneratorStructureState.class.getDeclaredField( - Refraction.pickName("hasGeneratedPositions", "h") - ); - hasGeneratedPositionsField.setAccessible(true); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - //runtime - private ServerLevel originalServerWorld; - private ServerChunkCache originalChunkProvider; - private ServerLevel freshWorld; - private ServerChunkCache freshChunkProvider; - private LevelStorageSource.LevelStorageAccess session; - private StructureTemplateManager structureTemplateManager; - private ThreadedLevelLightEngine threadedLevelLightEngine; - private ChunkGenerator chunkGenerator; - - private Path tempDir; - - private boolean generateFlatBedrock = false; - - public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) { - super(originalBukkitWorld, region, target, options); - } - - @Override - protected boolean prepare() { - this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle(); - originalChunkProvider = originalServerWorld.getChunkSource(); - - //flat bedrock? (only on paper) - if (paperConfigField != null) { - try { - generateFlatBedrock = flatBedrockField.getBoolean(paperConfigField.get(originalServerWorld)); - } catch (Exception ignored) { - } - } - - seed = options.getSeed().orElse(originalServerWorld.getSeed()); - chunkStati.forEach((s, c) -> super.chunkStatuses.put(new ChunkStatusWrap(s), c)); - - return true; - } - - @Override - @SuppressWarnings("unchecked") - protected boolean initNewWorld() throws Exception { - //world folder - tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen"); - - //prepare for world init (see upstream implementation for reference) - org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment(); - org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator(); - LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir); - ResourceKey levelStemResourceKey = getWorldDimKey(environment); - session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey); - PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData; - - MinecraftServer server = originalServerWorld.getCraftServer().getServer(); - WorldOptions originalOpts = originalWorldData.worldGenOptions(); - WorldOptions newOpts = options.getSeed().isPresent() - ? originalOpts.withSeed(OptionalLong.of(seed)) - : originalOpts; - LevelSettings newWorldSettings = new LevelSettings( - "faweregentempworld", - originalWorldData.settings.gameType(), - originalWorldData.settings.hardcore(), - originalWorldData.settings.difficulty(), - originalWorldData.settings.allowCommands(), - originalWorldData.settings.gameRules(), - originalWorldData.settings.getDataConfiguration() - ); - - PrimaryLevelData.SpecialWorldProperty specialWorldProperty = - originalWorldData.isFlatWorld() - ? PrimaryLevelData.SpecialWorldProperty.FLAT - : originalWorldData.isDebugWorld() - ? PrimaryLevelData.SpecialWorldProperty.DEBUG - : PrimaryLevelData.SpecialWorldProperty.NONE; - PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable()); - - BiomeProvider biomeProvider = getBiomeProvider(); - - - //init world - freshWorld = Fawe.instance().getQueueHandler().sync((Supplier) () -> new ServerLevel( - server, - server.executor, - session, - newWorldData, - originalServerWorld.dimension(), - DedicatedServer.getServer().registryAccess().registry(Registries.LEVEL_STEM).orElseThrow() - .getOrThrow(levelStemResourceKey), - new RegenNoOpWorldLoadListener(), - originalServerWorld.isDebug(), - seed, - ImmutableList.of(), - false, - environment, - generator, - biomeProvider - ) { - - private final Holder singleBiome = options.hasBiomeType() ? DedicatedServer.getServer().registryAccess() - .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( - WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) - ) : null; - - @Override - public void tick(BooleanSupplier shouldKeepTicking) { //no ticking - } - - @Override - public Holder getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { - if (options.hasBiomeType()) { - return singleBiome; - } - return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome( - biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler() - ); - } - }).get(); - freshWorld.noSave = true; - removeWorldFromWorldsMap(); - newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name - if (paperConfigField != null) { - paperConfigField.set(freshWorld, originalServerWorld.paperConfig()); - } - - ChunkGenerator originalGenerator = originalChunkProvider.getGenerator(); - if (originalGenerator instanceof FlatLevelSource flatLevelSource) { - FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings(); - chunkGenerator = new FlatLevelSource(generatorSettingFlat); - } else if (originalGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) { - Holder generatorSettingBaseSupplier = (Holder) generatorSettingBaseSupplierField.get( - originalGenerator); - BiomeSource biomeSource; - if (options.hasBiomeType()) { - - biomeSource = new FixedBiomeSource( - DedicatedServer.getServer().registryAccess() - .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( - WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) - ) - ); - } else { - biomeSource = originalGenerator.getBiomeSource(); - } - chunkGenerator = new NoiseBasedChunkGenerator( - biomeSource, - generatorSettingBaseSupplier - ); - } else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) { - chunkGenerator = customChunkGenerator.getDelegate(); - } else { - LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName()); - return false; - } - if (generator != null) { - chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator); - generateConcurrent = generator.isParallelCapable(); - } -// chunkGenerator.conf = freshWorld.spigotConfig; - Does not exist anymore, may need to be re-addressed - - freshChunkProvider = new ServerChunkCache( - freshWorld, - session, - server.getFixerUpper(), - server.getStructureManager(), - server.executor, - chunkGenerator, - freshWorld.spigotConfig.viewDistance, - freshWorld.spigotConfig.simulationDistance, - server.forceSynchronousWrites(), - new RegenNoOpWorldLoadListener(), - (chunkCoordIntPair, state) -> { - }, - () -> server.overworld().getDataStorage() - ) { - // redirect to LevelChunks created in #createChunks - @Override - public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean create) { - ChunkAccess chunkAccess = getChunkAt(x, z); - if (chunkAccess == null && create) { - chunkAccess = createChunk(getProtoChunkAt(x, z)); - } - return chunkAccess; - } - }; - - if (seed == originalOpts.seed() && !options.hasBiomeType()) { - // Optimisation for needless ring position calculation when the seed and biome is the same. - ChunkGeneratorStructureState state = (ChunkGeneratorStructureState) generatorStructureStateField.get(originalChunkProvider.chunkMap); - boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(state); - if (hasGeneratedPositions) { - Map>> origPositions = - (Map>>) ringPositionsField.get(state); - Map>> copy = new Object2ObjectArrayMap<>( - origPositions); - ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get(freshChunkProvider.chunkMap); - ringPositionsField.set(newState, copy); - hasGeneratedPositionsField.setBoolean(newState, true); - } - } - - - chunkSourceField.set(freshWorld, freshChunkProvider); - //let's start then - structureTemplateManager = server.getStructureManager(); - threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider); - - return true; - } - - @Override - protected void cleanup() { - try { - session.close(); - } catch (Exception ignored) { - } - - //shutdown chunk provider - try { - Fawe.instance().getQueueHandler().sync(() -> { - try { - freshChunkProvider.close(false); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - } catch (Exception ignored) { - } - - //remove world from server - try { - Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap); - } catch (Exception ignored) { - } - - //delete directory - try { - SafeFiles.tryHardToDeleteDir(tempDir); - } catch (Exception ignored) { - } - } - - @Override - protected ProtoChunk createProtoChunk(int x, int z) { - return new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld, - this.freshWorld.registryAccess().registryOrThrow(BIOME), null - ); - } - - @Override - protected LevelChunk createChunk(ProtoChunk protoChunk) { - return new LevelChunk( - freshWorld, - protoChunk, - null // we don't want to add entities - ); - } - - @Override - protected ChunkStatusWrap getFullChunkStatus() { - return new ChunkStatusWrap(ChunkStatus.FULL); - } - - @Override - protected List getBlockPopulators() { - return originalServerWorld.getWorld().getPopulators(); - } - - @Override - protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) { - // BlockPopulator#populate has to be called synchronously for TileEntity access - TaskManager.taskManager().task(() -> { - final CraftWorld world = freshWorld.getWorld(); - final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ); - blockPopulator.populate(world, random, chunk); - }); - } - - @Override - protected IChunkCache initSourceQueueCache() { - return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) { - @Override - public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) { - return getChunkAt(x, z); - } - }; - } - - //util - @SuppressWarnings("unchecked") - private void removeWorldFromWorldsMap() { - Fawe.instance().getQueueHandler().sync(() -> { - try { - Map map = (Map) serverWorldsField.get(Bukkit.getServer()); - map.remove("faweregentempworld"); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - }); - } - - private ResourceKey getWorldDimKey(org.bukkit.World.Environment env) { - return switch (env) { - case NETHER -> LevelStem.NETHER; - case THE_END -> LevelStem.END; - default -> LevelStem.OVERWORLD; - }; - } - - private static class RegenNoOpWorldLoadListener implements ChunkProgressListener { - - private RegenNoOpWorldLoadListener() { - } - - @Override - public void updateSpawnPos(ChunkPos spawnPos) { - } - - @Override - public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) { - } - - @Override - public void start() { - - } - - @Override - public void stop() { - } - - // TODO Paper only(?) @Override - public void setChunkRadius(int radius) { - } - - } - - private class FastProtoChunk extends ProtoChunk { - - public FastProtoChunk( - final ChunkPos pos, - final UpgradeData upgradeData, - final LevelHeightAccessor world, - final Registry biomeRegistry, - @Nullable final BlendingData blendingData - ) { - super(pos, upgradeData, world, biomeRegistry, blendingData); - } - - // avoid warning on paper - - // compatibility with spigot - - public boolean generateFlatBedrock() { - return generateFlatBedrock; - } - - // no one will ever see the entities! - @Override - public List getEntities() { - return Collections.emptyList(); - } - - } - - protected class ChunkStatusWrap extends ChunkStatusWrapper { - - private final ChunkStatus chunkStatus; - - public ChunkStatusWrap(ChunkStatus chunkStatus) { - this.chunkStatus = chunkStatus; - } - - @Override - public int requiredNeighborChunkRadius() { - return chunkStatus.getRange(); - } - - @Override - public String name() { - return chunkStatus.getName(); - } - - @Override - public CompletableFuture processChunk(List accessibleChunks) { - return chunkStatus.generate( - Runnable::run, // TODO revisit, we might profit from this somehow? - freshWorld, - chunkGenerator, - structureTemplateManager, - threadedLevelLightEngine, - c -> CompletableFuture.completedFuture(Either.left(c)), - accessibleChunks, - true - ); - } - - } - - /** - * A light engine that does nothing. As light is calculated after pasting anyway, we can avoid - * work this way. - */ - static class NoOpLightEngine extends ThreadedLevelLightEngine { - - private static final ProcessorMailbox MAILBOX = ProcessorMailbox.create(task -> { - }, "fawe-no-op"); - private static final ProcessorHandle> HANDLE = ProcessorHandle.of("fawe-no-op", m -> { - }); - - public NoOpLightEngine(final ServerChunkCache chunkProvider) { - super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE); - } - - @Override - public CompletableFuture retainData(final ChunkAccess chunk) { - return CompletableFuture.completedFuture(chunk); - } - - @Override - public CompletableFuture lightChunk(final ChunkAccess chunk, final boolean excludeBlocks) { - return CompletableFuture.completedFuture(chunk); - } - - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts deleted file mode 100644 index 51438592a..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts +++ /dev/null @@ -1,17 +0,0 @@ -import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension - -plugins { - java -} - -applyPaperweightAdapterConfiguration() - -repositories { - gradlePluginPortal() -} - -dependencies { - // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.1-R0.1-SNAPSHOT - the().paperDevBundle("1.20.1-R0.1-20230921.165944-178") - compileOnly(libs.paperlib) -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java deleted file mode 100644 index 0cecbb45b..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java +++ /dev/null @@ -1,1131 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Sets; -import com.google.common.util.concurrent.Futures; -import com.mojang.datafixers.util.Either; -import com.mojang.serialization.Lifecycle; -import com.sk89q.jnbt.NBTConstants; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.blocks.BaseItem; -import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.PaperweightPlatformAdapter; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.extension.platform.Watchdog; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.Constants; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; -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.util.SideEffect; -import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; -import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.world.DataFixer; -import com.sk89q.worldedit.world.RegenOptions; -import com.sk89q.worldedit.world.biome.BiomeCategory; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.BiomeTypes; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.item.ItemType; -import net.minecraft.Util; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.HolderSet; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; -import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.progress.ChunkProgressListener; -import net.minecraft.util.StringRepresentable; -import net.minecraft.util.thread.BlockableEventLoop; -import net.minecraft.world.Clearable; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelSettings; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.StructureBlockEntity; -import net.minecraft.world.level.block.state.StateDefinition; -import net.minecraft.world.level.block.state.properties.DirectionProperty; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.WorldOptions; -import net.minecraft.world.level.storage.LevelStorageSource; -import net.minecraft.world.level.storage.PrimaryLevelData; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World.Environment; -import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_20_R1.CraftServer; -import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_20_R1.util.CraftMagicNumbers; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; -import org.bukkit.generator.ChunkGenerator; -import org.enginehub.linbus.common.LinTagId; -import org.enginehub.linbus.tree.LinByteArrayTag; -import org.enginehub.linbus.tree.LinByteTag; -import org.enginehub.linbus.tree.LinCompoundTag; -import org.enginehub.linbus.tree.LinDoubleTag; -import org.enginehub.linbus.tree.LinEndTag; -import org.enginehub.linbus.tree.LinFloatTag; -import org.enginehub.linbus.tree.LinIntArrayTag; -import org.enginehub.linbus.tree.LinIntTag; -import org.enginehub.linbus.tree.LinListTag; -import org.enginehub.linbus.tree.LinLongArrayTag; -import org.enginehub.linbus.tree.LinLongTag; -import org.enginehub.linbus.tree.LinShortTag; -import org.enginehub.linbus.tree.LinStringTag; -import org.enginehub.linbus.tree.LinTag; -import org.enginehub.linbus.tree.LinTagType; -import org.spigotmc.SpigotConfig; -import org.spigotmc.WatchdogThread; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.OptionalInt; -import java.util.OptionalLong; -import java.util.Set; -import java.util.TreeMap; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -public final class PaperweightAdapter implements BukkitImplAdapter { - - private final Logger logger = Logger.getLogger(getClass().getCanonicalName()); - - private final Field serverWorldsField; - private final Method getChunkFutureMethod; - private final Field chunkProviderExecutorField; - private final Watchdog watchdog; - - // ------------------------------------------------------------------------ - // Code that may break between versions of Minecraft - // ------------------------------------------------------------------------ - - public PaperweightAdapter() throws NoSuchFieldException, NoSuchMethodException { - // A simple test - CraftServer.class.cast(Bukkit.getServer()); - - int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); - if (dataVersion != 3463 && dataVersion != 3465) { - throw new UnsupportedClassVersionError("Not 1.20(.1)!"); - } - - serverWorldsField = CraftServer.class.getDeclaredField("worlds"); - serverWorldsField.setAccessible(true); - - getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod( - Refraction.pickName("getChunkFutureMainThread", "c"), - int.class, int.class, ChunkStatus.class, boolean.class - ); - getChunkFutureMethod.setAccessible(true); - - chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField( - Refraction.pickName("mainThreadProcessor", "g") - ); - chunkProviderExecutorField.setAccessible(true); - - new PaperweightDataConverters(CraftMagicNumbers.INSTANCE.getDataVersion(), this).buildUnoptimized(); - - Watchdog watchdog; - try { - Class.forName("org.spigotmc.WatchdogThread"); - watchdog = new SpigotWatchdog(); - } catch (ClassNotFoundException | NoSuchFieldException e) { - try { - watchdog = new MojangWatchdog(((CraftServer) Bukkit.getServer()).getServer()); - } catch (NoSuchFieldException ex) { - watchdog = null; - } - } - this.watchdog = watchdog; - - try { - Class.forName("org.spigotmc.SpigotConfig"); - SpigotConfig.config.set("world-settings.faweregentempworld.verbose", false); - } catch (ClassNotFoundException ignored) { - } - } - - @Override - public DataFixer getDataFixer() { - return PaperweightDataConverters.INSTANCE; - } - - /** - * Read the given NBT data into the given tile entity. - * - * @param tileEntity the tile entity - * @param tag the tag - */ - static void readTagIntoTileEntity(net.minecraft.nbt.CompoundTag tag, BlockEntity tileEntity) { - tileEntity.load(tag); - tileEntity.setChanged(); - } - - /** - * Get the ID string of the given entity. - * - * @param entity the entity - * @return the entity ID - */ - private static String getEntityId(Entity entity) { - return EntityType.getKey(entity.getType()).toString(); - } - - /** - * Create an entity using the given entity ID. - * - * @param id the entity ID - * @param world the world - * @return an entity or null - */ - @Nullable - private static Entity createEntityFromId(String id, net.minecraft.world.level.Level world) { - return EntityType.byString(id).map(t -> t.create(world)).orElse(null); - } - - /** - * Write the given NBT data into the given entity. - * - * @param entity the entity - * @param tag the tag - */ - private static void readTagIntoEntity(net.minecraft.nbt.CompoundTag tag, Entity entity) { - entity.load(tag); - } - - /** - * Write the entity's NBT data to the given tag. - * - * @param entity the entity - * @param tag the tag - */ - private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag tag) { - //FAWE start - avoid villager async catcher - PaperweightPlatformAdapter.readEntityIntoTag(entity, tag); - //FAWE end - } - - private static Block getBlockFromType(BlockType blockType) { - - return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK).get(ResourceLocation.tryParse(blockType.id())); - } - - private static Item getItemFromType(ItemType itemType) { - return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(itemType.id())); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockData data) { - net.minecraft.world.level.block.state.BlockState state = ((CraftBlockData) data).getState(); - int combinedId = Block.getId(state); - return combinedId == 0 && state.getBlock() != Blocks.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockState state) { - Block mcBlock = getBlockFromType(state.getBlockType()); - net.minecraft.world.level.block.state.BlockState newState = mcBlock.defaultBlockState(); - Map, Object> states = state.getStates(); - newState = applyProperties(mcBlock.getStateDefinition(), newState, states); - final int combinedId = Block.getId(newState); - return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); - } - - public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) { - int internalId = Block.getId(blockState); - BlockState state = BlockStateIdAccess.getBlockStateById(internalId); - if (state == null) { - state = BukkitAdapter.adapt(CraftBlockData.createData(blockState)); - } - - return state; - } - - public BiomeType adapt(Biome biome) { - var mcBiome = ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getKey(biome); - if (mcBiome == null) { - return null; - } - return BiomeType.REGISTRY.get(mcBiome.toString()); - } - - public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockState) { - int internalId = BlockStateIdAccess.getBlockStateId(blockState); - return Block.stateById(internalId); - } - - @Override - public BlockState getBlock(Location location) { - checkNotNull(location); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - int internalId = Block.getId(blockData); - BlockState state = BlockStateIdAccess.getBlockStateById(internalId); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - - return state; - } - - @Override - public BaseBlock getFullBlock(Location location) { - BlockState state = getBlock(location); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - - // Read the NBT data - BlockEntity te = chunk.getBlockEntity(blockPos); - if (te != null) { - net.minecraft.nbt.CompoundTag tag = te.saveWithId(); - return state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); - } - - return state.toBaseBlock(); - } -/* - @Override - public boolean hasCustomBiomeSupport() { - return true; - } -*/ - private static final HashMap> biomeTypeToNMSCache = new HashMap<>(); - private static final HashMap, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); - - /* @Override - public BiomeType getBiome(Location location) { - checkNotNull(location); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - - return biomeTypeFromNMSCache.computeIfAbsent(chunk.getNoiseBiome(x >> 2, y >> 2, z >> 2), b -> BiomeType.REGISTRY.get(b.unwrapKey().get().location().toString())); - } - - @Override - public void setBiome(Location location, BiomeType biome) { - checkNotNull(location); - checkNotNull(biome); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - chunk.setBiome(x >> 2, y >> 2, z >> 2, biomeTypeToNMSCache.computeIfAbsent(biome, b -> ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(ResourceKey.create(Registries.BIOME, new ResourceLocation(b.getId()))))); - chunk.setUnsaved(true); - }*/ - - @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1.PaperweightWorldNativeAccess(this, - new WeakReference<>(((CraftWorld) world).getHandle())); - } - - private static net.minecraft.core.Direction adapt(Direction face) { - switch (face) { - case NORTH: - return net.minecraft.core.Direction.NORTH; - case SOUTH: - return net.minecraft.core.Direction.SOUTH; - case WEST: - return net.minecraft.core.Direction.WEST; - case EAST: - return net.minecraft.core.Direction.EAST; - case DOWN: - return net.minecraft.core.Direction.DOWN; - case UP: - default: - return net.minecraft.core.Direction.UP; - } - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - private net.minecraft.world.level.block.state.BlockState applyProperties( - StateDefinition stateContainer, - net.minecraft.world.level.block.state.BlockState newState, - Map, Object> states - ) { - for (Map.Entry, Object> state : states.entrySet()) { - net.minecraft.world.level.block.state.properties.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.world.level.block.state.properties.EnumProperty) { - String enumName = (String) value; - value = ((net.minecraft.world.level.block.state.properties.EnumProperty) property) - .getValue(enumName).orElseThrow(() -> - new IllegalStateException( - "Enum property " + property.getName() + " does not contain " + enumName - ) - ); - } - - newState = newState.setValue( - (net.minecraft.world.level.block.state.properties.Property) property, - (Comparable) value - ); - } - return newState; - } - - @Override - public BaseEntity getEntity(org.bukkit.entity.Entity entity) { - checkNotNull(entity); - - CraftEntity craftEntity = ((CraftEntity) entity); - Entity mcEntity = craftEntity.getHandle(); - - // Do not allow creating of passenger entity snapshots, passengers are included in the vehicle entity - if (mcEntity.isPassenger()) { - return null; - } - - String id = getEntityId(mcEntity); - - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - readEntityIntoTag(mcEntity, tag); - return new BaseEntity( - com.sk89q.worldedit.world.entity.EntityTypes.get(id), - LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) - ); - } - - @Nullable - @Override - public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state) { - checkNotNull(location); - checkNotNull(state); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - ServerLevel worldServer = craftWorld.getHandle(); - - Entity createdEntity = createEntityFromId(state.getType().id(), craftWorld.getHandle()); - - if (createdEntity != null) { - LinCompoundTag nativeTag = state.getNbt(); - if (nativeTag != null) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeLin(nativeTag); - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - readTagIntoEntity(tag, createdEntity); - } - - createdEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - - worldServer.addFreshEntity(createdEntity, SpawnReason.CUSTOM); - return createdEntity.getBukkitEntity(); - } else { - return null; - } - } - - // This removes all unwanted tags from the main entity and all its passengers - private void removeUnwantedEntityTagsRecursively(net.minecraft.nbt.CompoundTag tag) { - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - - // Adapted from net.minecraft.world.entity.EntityType#loadEntityRecursive - if (tag.contains("Passengers", NBTConstants.TYPE_LIST)) { - net.minecraft.nbt.ListTag nbttaglist = tag.getList("Passengers", NBTConstants.TYPE_COMPOUND); - - for (int i = 0; i < nbttaglist.size(); ++i) { - removeUnwantedEntityTagsRecursively(nbttaglist.getCompound(i)); - } - } - } - - @Override - public Component getRichBlockName(BlockType blockType) { - return TranslatableComponent.of(getBlockFromType(blockType).getDescriptionId()); - } - - @Override - public Component getRichItemName(ItemType itemType) { - return TranslatableComponent.of(getItemFromType(itemType).getDescriptionId()); - } - - @Override - public Component getRichItemName(BaseItemStack itemStack) { - return TranslatableComponent.of(CraftItemStack.asNMSCopy(BukkitAdapter.adapt(itemStack)).getDescriptionId()); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - private static final LoadingCache> PROPERTY_CACHE = CacheBuilder - .newBuilder() - .build(new CacheLoader<>() { - @Override - public Property load(net.minecraft.world.level.block.state.properties.Property state) { - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else if (state instanceof DirectionProperty) { - return new DirectionalProperty( - state.getName(), - new ArrayList<>((List) state - .getPossibleValues() - .stream() - .map(e -> Direction.valueOf(((StringRepresentable) e) - .getSerializedName() - .toUpperCase(Locale.ROOT))) - .toList()) - ); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - return new EnumProperty( - state.getName(), - new ArrayList<>((List) state - .getPossibleValues() - .stream() - .map(e -> ((StringRepresentable) e).getSerializedName()) - .toList()) - ); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else { - throw new IllegalArgumentException("WorldEdit needs an update to support " + state - .getClass() - .getSimpleName()); - } - } - }); - - @SuppressWarnings({ "rawtypes" }) - @Override - public Map> getProperties(BlockType blockType) { - Map> properties = new TreeMap<>(); - Block block = getBlockFromType(blockType); - StateDefinition blockStateList = - block.getStateDefinition(); - for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { - Property property = PROPERTY_CACHE.getUnchecked(state); - properties.put(property.getName(), property); - } - return properties; - } - - @Override - public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) { - ((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create( - new StructureBlockEntity( - new BlockPos(pos.x(), pos.y(), pos.z()), - Blocks.STRUCTURE_BLOCK.defaultBlockState() - ), - __ -> (net.minecraft.nbt.CompoundTag) fromNativeLin(nbtData) - )); - } - - @Override - public void sendFakeOP(Player player) { - ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( - ((CraftPlayer) player).getHandle(), (byte) 28 - )); - } - - @Override - public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { - ItemStack stack = new ItemStack( - DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().id())), - item.getAmount() - ); - stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData()))); - return CraftItemStack.asCraftMirror(stack); - } - - @Override - public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { - final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); - final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); - weStack.setNbt(((LinCompoundTag) toNativeLin(nmsStack.getTag()))); - return weStack; - } - - private final LoadingCache fakePlayers - = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); - - @Override - public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) { - CraftWorld craftWorld = (CraftWorld) world; - ServerLevel worldServer = craftWorld.getHandle(); - ItemStack stack = CraftItemStack.asNMSCopy(BukkitAdapter.adapt(item instanceof BaseItemStack - ? ((BaseItemStack) item) : new BaseItemStack(item.getType(), item.getNbtData(), 1))); - stack.setTag((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData())); - - PaperweightFakePlayer fakePlayer; - try { - fakePlayer = fakePlayers.get(worldServer); - } catch (ExecutionException ignored) { - return false; - } - fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); - fakePlayer.absMoveTo(position.x(), position.y(), position.z(), - (float) face.toVector().toYaw(), (float) face.toVector().toPitch()); - - final BlockPos blockPos = new BlockPos(position.x(), position.y(), position.z()); - final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos); - final net.minecraft.core.Direction enumFacing = adapt(face); - BlockHitResult rayTrace = new BlockHitResult(blockVec, enumFacing, blockPos, false); - UseOnContext context = new UseOnContext(fakePlayer, InteractionHand.MAIN_HAND, rayTrace); - InteractionResult result = stack.useOn(context); - if (result != InteractionResult.SUCCESS) { - if (worldServer.getBlockState(blockPos).use(worldServer, fakePlayer, InteractionHand.MAIN_HAND, rayTrace).consumesAction()) { - result = InteractionResult.SUCCESS; - } else { - result = stack.getItem().use(worldServer, fakePlayer, InteractionHand.MAIN_HAND).getResult(); - } - } - - return result == InteractionResult.SUCCESS; - } - - @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 position, BlockState blockState) { - int internalId = BlockStateIdAccess.getBlockStateId(blockState); - net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId); - return blockData.canSurvive(((CraftWorld) world).getHandle(), new BlockPos(position.x(), position.y(), position.z())); - } - - @Override - public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) { - try { - doRegen(bukkitWorld, region, extent, options); - } catch (Exception e) { - throw new IllegalStateException("Regen failed.", e); - } - - return true; - } - - private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { - Environment env = bukkitWorld.getEnvironment(); - ChunkGenerator gen = bukkitWorld.getGenerator(); - - Path tempDir = Files.createTempDirectory("WorldEditWorldGen"); - LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir); - ResourceKey worldDimKey = getWorldDimKey(env); - try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { - ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); - PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() - .getWorldData().overworldData(); - WorldOptions originalOpts = levelProperties.worldGenOptions(); - - long seed = options.getSeed().orElse(originalWorld.getSeed()); - WorldOptions newOpts = options.getSeed().isPresent() - ? originalOpts.withSeed(OptionalLong.of(seed)) - : originalOpts; - - LevelSettings newWorldSettings = new LevelSettings( - "faweregentempworld", - levelProperties.settings.gameType(), - levelProperties.settings.hardcore(), - levelProperties.settings.difficulty(), - levelProperties.settings.allowCommands(), - levelProperties.settings.gameRules(), - levelProperties.settings.getDataConfiguration() - ); - - PrimaryLevelData.SpecialWorldProperty specialWorldProperty = - levelProperties.isFlatWorld() - ? PrimaryLevelData.SpecialWorldProperty.FLAT - : levelProperties.isDebugWorld() - ? PrimaryLevelData.SpecialWorldProperty.DEBUG - : PrimaryLevelData.SpecialWorldProperty.NONE; - - PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable()); - - ServerLevel freshWorld = new ServerLevel( - originalWorld.getServer(), - originalWorld.getServer().executor, - session, newWorldData, - originalWorld.dimension(), - new LevelStem( - originalWorld.dimensionTypeRegistration(), - originalWorld.getChunkSource().getGenerator() - ), - new NoOpWorldLoadListener(), - originalWorld.isDebug(), - seed, - ImmutableList.of(), - false, - originalWorld.getRandomSequences(), - env, - gen, - bukkitWorld.getBiomeProvider() - ); - try { - regenForWorld(region, extent, freshWorld, options); - } finally { - freshWorld.getChunkSource().close(false); - } - } finally { - try { - @SuppressWarnings("unchecked") - Map map = (Map) serverWorldsField.get(Bukkit.getServer()); - map.remove("faweregentempworld"); - } catch (IllegalAccessException ignored) { - } - SafeFiles.tryHardToDeleteDir(tempDir); - } - } - - private BiomeType adapt(ServerLevel serverWorld, Biome origBiome) { - ResourceLocation key = serverWorld.registryAccess().registryOrThrow(Registries.BIOME).getKey(origBiome); - if (key == null) { - return null; - } - return BiomeTypes.get(key.toString()); - } - - @SuppressWarnings("unchecked") - private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld, RegenOptions options) throws WorldEditException { - List> chunkLoadings = submitChunkLoadTasks(region, serverWorld); - BlockableEventLoop executor; - try { - executor = (BlockableEventLoop) chunkProviderExecutorField.get(serverWorld.getChunkSource()); - } catch (IllegalAccessException e) { - throw new IllegalStateException("Couldn't get executor for chunk loading.", e); - } - executor.managedBlock(() -> { - // bail out early if a future fails - if (chunkLoadings.stream().anyMatch(ftr -> - ftr.isDone() && Futures.getUnchecked(ftr) == null - )) { - return false; - } - return chunkLoadings.stream().allMatch(CompletableFuture::isDone); - }); - Map chunks = new HashMap<>(); - for (CompletableFuture future : chunkLoadings) { - @Nullable - ChunkAccess chunk = future.getNow(null); - checkState(chunk != null, "Failed to generate a chunk, regen failed."); - chunks.put(chunk.getPos(), chunk); - } - - for (BlockVector3 vec : region) { - BlockPos pos = new BlockPos(vec.x(), vec.y(), vec.z()); - ChunkAccess chunk = chunks.get(new ChunkPos(pos)); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(pos); - int internalId = Block.getId(blockData); - BlockStateHolder state = BlockStateIdAccess.getBlockStateById(internalId); - Objects.requireNonNull(state); - BlockEntity blockEntity = chunk.getBlockEntity(pos); - if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); - state = state.toBaseBlock(((LinCompoundTag) toNativeLin(tag))); - } - extent.setBlock(vec, state.toBaseBlock()); - if (options.shouldRegenBiomes()) { - Biome origBiome = chunk.getNoiseBiome(vec.x(), vec.y(), vec.z()).value(); - BiomeType adaptedBiome = adapt(serverWorld, origBiome); - if (adaptedBiome != null) { - extent.setBiome(vec, adaptedBiome); - } - } - } - } - - @SuppressWarnings("unchecked") - private List> submitChunkLoadTasks(Region region, ServerLevel serverWorld) { - ServerChunkCache chunkManager = serverWorld.getChunkSource(); - List> chunkLoadings = new ArrayList<>(); - // Pre-gen all the chunks - for (BlockVector2 chunk : region.getChunks()) { - try { - //noinspection unchecked - chunkLoadings.add( - ((CompletableFuture>) - getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) - .thenApply(either -> either.left().orElse(null)) - ); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalStateException("Couldn't load chunk for regen.", e); - } - } - return chunkLoadings; - } - - private ResourceKey getWorldDimKey(Environment env) { - switch (env) { - case NETHER: - return LevelStem.NETHER; - case THE_END: - return LevelStem.END; - case NORMAL: - default: - return LevelStem.OVERWORLD; - } - } - - private static final Set SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( - SideEffect.NEIGHBORS, - SideEffect.LIGHTING, - SideEffect.VALIDATION, - SideEffect.ENTITY_AI, - SideEffect.EVENTS, - SideEffect.UPDATE - ); - - @Override - public Set getSupportedSideEffects() { - return SUPPORTED_SIDE_EFFECTS; - } - - @Override - public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) { - ServerLevel originalWorld = ((CraftWorld) world).getHandle(); - - BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z())); - if (entity instanceof Clearable) { - ((Clearable) entity).clearContent(); - return true; - } - return false; - } - - @Override - public void initializeRegistries() { - DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer(); - // Biomes - for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.BIOME).keySet()) { - if (BiomeType.REGISTRY.get(name.toString()) == null) { - BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString())); - } - } - - // BiomeCategories - Registry biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); - biomeRegistry.getTagNames().forEach(tagKey -> { - String key = tagKey.location().toString(); - if (BiomeCategory.REGISTRY.get(key) == null) { - BiomeCategory.REGISTRY.register(key, new BiomeCategory( - key, - () -> biomeRegistry.getTag(tagKey) - .stream() - .flatMap(HolderSet.Named::stream) - .map(Holder::value) - .map(this::adapt) - .collect(Collectors.toSet())) - ); - } - }); - } - // ------------------------------------------------------------------------ - // Code that is less likely to break - // ------------------------------------------------------------------------ - - /** - * Converts from a non-native NMS NBT structure to a native WorldEdit NBT - * structure. - * - * @param foreign non-native NMS NBT structure - * @return native WorldEdit NBT structure - */ - @Override - public LinTag toNativeLin(net.minecraft.nbt.Tag foreign) { - if (foreign == null) { - return null; - } - if (foreign instanceof net.minecraft.nbt.CompoundTag) { - Map> values = new HashMap<>(); - Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); - - for (String str : foreignKeys) { - net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); - values.put(str, toNativeLin(base)); - } - return LinCompoundTag.of(values); - } else if (foreign instanceof net.minecraft.nbt.ByteTag) { - return LinByteTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); - } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { - return LinByteArrayTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); - } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { - return LinDoubleTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); - } else if (foreign instanceof net.minecraft.nbt.FloatTag) { - return LinFloatTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); - } else if (foreign instanceof net.minecraft.nbt.IntTag) { - return LinIntTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); - } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { - return LinIntArrayTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); - } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { - return LinLongArrayTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); - } else if (foreign instanceof net.minecraft.nbt.ListTag) { - try { - return toNativeLinList((net.minecraft.nbt.ListTag) foreign); - } catch (Throwable e) { - logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); - } - } else if (foreign instanceof net.minecraft.nbt.LongTag) { - return LinLongTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); - } else if (foreign instanceof net.minecraft.nbt.ShortTag) { - return LinShortTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); - } else if (foreign instanceof net.minecraft.nbt.StringTag) { - return LinStringTag.of(foreign.getAsString()); - } else if (foreign instanceof net.minecraft.nbt.EndTag) { - return LinEndTag.instance(); - } - throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); - } - - /** - * Convert a foreign NBT list tag into a native WorldEdit one. - * - * @param foreign the foreign tag - * @return the converted tag - * @throws SecurityException on error - * @throws IllegalArgumentException on error - */ - private LinListTag toNativeLinList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { - LinListTag.Builder> builder = LinListTag.builder( - LinTagType.fromId(LinTagId.fromId(foreign.getElementType())) - ); - - for (net.minecraft.nbt.Tag tag : foreign) { - builder.add(toNativeLin(tag)); - } - - return builder.build(); - } - - /** - * Converts a WorldEdit-native NBT structure to a NMS structure. - * - * @param foreign structure to convert - * @return non-native structure - */ - @Override - public net.minecraft.nbt.Tag fromNativeLin(LinTag foreign) { - if (foreign == null) { - return null; - } - if (foreign instanceof LinCompoundTag compoundTag) { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - for (var entry : compoundTag.value().entrySet()) { - tag.put(entry.getKey(), fromNativeLin(entry.getValue())); - } - return tag; - } else if (foreign instanceof LinByteTag byteTag) { - return net.minecraft.nbt.ByteTag.valueOf(byteTag.valueAsByte()); - } else if (foreign instanceof LinByteArrayTag byteArrayTag) { - return new net.minecraft.nbt.ByteArrayTag(byteArrayTag.value()); - } else if (foreign instanceof LinDoubleTag doubleTag) { - return net.minecraft.nbt.DoubleTag.valueOf(doubleTag.valueAsDouble()); - } else if (foreign instanceof LinFloatTag floatTag) { - return net.minecraft.nbt.FloatTag.valueOf(floatTag.valueAsFloat()); - } else if (foreign instanceof LinIntTag intTag) { - return net.minecraft.nbt.IntTag.valueOf(intTag.valueAsInt()); - } else if (foreign instanceof LinIntArrayTag intArrayTag) { - return new net.minecraft.nbt.IntArrayTag(intArrayTag.value()); - } else if (foreign instanceof LinLongArrayTag longArrayTag) { - return new net.minecraft.nbt.LongArrayTag(longArrayTag.value()); - } else if (foreign instanceof LinListTag listTag) { - net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); - for (var t : listTag.value()) { - tag.add(fromNativeLin(t)); - } - return tag; - } else if (foreign instanceof LinLongTag longTag) { - return net.minecraft.nbt.LongTag.valueOf(longTag.valueAsLong()); - } else if (foreign instanceof LinShortTag shortTag) { - return net.minecraft.nbt.ShortTag.valueOf(shortTag.valueAsShort()); - } else if (foreign instanceof LinStringTag stringTag) { - return net.minecraft.nbt.StringTag.valueOf(stringTag.value()); - } else if (foreign instanceof LinEndTag) { - return net.minecraft.nbt.EndTag.INSTANCE; - } else { - throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); - } - } - - @Override - public boolean supportsWatchdog() { - return watchdog != null; - } - - @Override - public void tickWatchdog() { - watchdog.tick(); - } - - private class SpigotWatchdog implements Watchdog { - private final Field instanceField; - private final Field lastTickField; - - SpigotWatchdog() throws NoSuchFieldException { - Field instanceField = WatchdogThread.class.getDeclaredField("instance"); - instanceField.setAccessible(true); - this.instanceField = instanceField; - - Field lastTickField = WatchdogThread.class.getDeclaredField("lastTick"); - lastTickField.setAccessible(true); - this.lastTickField = lastTickField; - } - - @Override - public void tick() { - try { - WatchdogThread instance = (WatchdogThread) this.instanceField.get(null); - if ((long) lastTickField.get(instance) != 0) { - WatchdogThread.tick(); - } - } catch (IllegalAccessException e) { - logger.log(Level.WARNING, "Failed to tick watchdog", e); - } - } - } - - private static class MojangWatchdog implements Watchdog { - private final DedicatedServer server; - private final Field tickField; - - MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { - this.server = server; - Field tickField = MinecraftServer.class.getDeclaredField( - Refraction.pickName("nextTickTime", "ah") - ); - if (tickField.getType() != long.class) { - throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); - } - tickField.setAccessible(true); - this.tickField = tickField; - } - - @Override - public void tick() { - try { - tickField.set(server, Util.getMillis()); - } catch (IllegalAccessException ignored) { - } - } - } - - private static class NoOpWorldLoadListener implements ChunkProgressListener { - @Override - public void updateSpawnPos(ChunkPos spawnPos) { - } - - @Override - public void onStatusChange(ChunkPos pos, @org.jetbrains.annotations.Nullable ChunkStatus status) { - } - - @Override - public void start() { - } - - @Override - public void stop() { - } - - @Override - public void setChunkRadius(int radius) { - } - } -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightDataConverters.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightDataConverters.java deleted file mode 100644 index ebe674ca5..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightDataConverters.java +++ /dev/null @@ -1,2798 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1; - -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; -import com.mojang.datafixers.DSL.TypeReference; -import com.mojang.datafixers.DataFixer; -import com.mojang.datafixers.DataFixerBuilder; -import com.mojang.datafixers.schemas.Schema; -import com.mojang.serialization.Dynamic; -import net.minecraft.core.Direction; -import net.minecraft.nbt.NbtOps; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.GsonHelper; -import net.minecraft.util.StringUtil; -import net.minecraft.util.datafix.DataFixers; -import net.minecraft.util.datafix.fixes.References; -import net.minecraft.world.item.DyeColor; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.enginehub.linbus.tree.LinCompoundTag; - -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({ "rawtypes", "unchecked" }) -class PaperweightDataConverters 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((LinCompoundTag) original, srcVer); - } else if (type == FixTypes.BLOCK_ENTITY) { - return (T) fixBlockEntity((LinCompoundTag) original, srcVer); - } else if (type == FixTypes.ENTITY) { - return (T) fixEntity((LinCompoundTag) 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 LinCompoundTag fixChunk(LinCompoundTag originalChunk, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(originalChunk); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); - return (LinCompoundTag) adapter.toNativeLin(fixed); - } - - private LinCompoundTag fixBlockEntity(LinCompoundTag origTileEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origTileEnt); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); - return (LinCompoundTag) adapter.toNativeLin(fixed); - } - - private LinCompoundTag fixEntity(LinCompoundTag origEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origEnt); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); - return (LinCompoundTag) adapter.toNativeLin(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(References.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.contains("Properties", 10)) { - sb.append('['); - net.minecraft.nbt.CompoundTag props = tagCompound.getCompound("Properties"); - sb.append(props.getAllKeys().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, References.BIOME); - } - - private String fixItemType(String key, int srcVer) { - return fixName(key, srcVer, References.ITEM_NAME); - } - - private static String fixName(String key, int srcVer, TypeReference type) { - return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, net.minecraft.nbt.StringTag.valueOf(key)), srcVer, DATA_VERSION) - .getValue().getAsString(); - } - - private final PaperweightAdapter adapter; - - private static final NbtOps OPS_NBT = NbtOps.INSTANCE; - private static final int LEGACY_VERSION = 1343; - private static int DATA_VERSION; - static PaperweightDataConverters 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(References.LEVEL), - PLAYER(References.PLAYER), - CHUNK(References.CHUNK), - BLOCK_ENTITY(References.BLOCK_ENTITY), - ENTITY(References.ENTITY), - ITEM_INSTANCE(References.ITEM_STACK), - OPTIONS(References.OPTIONS), - STRUCTURE(References.STRUCTURE); - - private final TypeReference type; - - LegacyType(TypeReference type) { - this.type = type; - DFU_TO_LEGACY.put(type.typeName(), this); - } - - public TypeReference getDFUType() { - return type; - } - } - - PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { - super(dataVersion); - DATA_VERSION = dataVersion; - INSTANCE = this; - this.adapter = adapter; - registerConverters(); - registerInspectors(); - } - - - // Called after fixers are built and ready for FIXING - @Override - public DataFixer buildUnoptimized() { - return this.fixer = new WrappedDataFixer(DataFixers.getDataFixer()); - } - - @Override - public DataFixer buildOptimized(final Set requiredTypes, Executor executor) { - return buildUnoptimized(); - } - - @SuppressWarnings("unchecked") - 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 = PaperweightDataConverters.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 = PaperweightDataConverters.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.contains("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 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, 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.contains(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.contains(key, 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound.getList(key, 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - nbttaglist.set(j, convert(LegacyType.ITEM_INSTANCE, nbttaglist.getCompound(j), sourceVer, targetVer)); - } - } - - } - - private static class DataConverterEquipment implements DataConverter { - - DataConverterEquipment() { - } - - public int getDataVersion() { - return 100; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("Equipment", 10); - net.minecraft.nbt.ListTag nbttaglist1; - - if (!nbttaglist.isEmpty() && !cmp.contains("HandItems", 10)) { - nbttaglist1 = new net.minecraft.nbt.ListTag(); - nbttaglist1.add(nbttaglist.get(0)); - nbttaglist1.add(new net.minecraft.nbt.CompoundTag()); - cmp.put("HandItems", nbttaglist1); - } - - if (nbttaglist.size() > 1 && !cmp.contains("ArmorItem", 10)) { - nbttaglist1 = new net.minecraft.nbt.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.contains("DropChances", 9)) { - nbttaglist1 = cmp.getList("DropChances", 5); - net.minecraft.nbt.ListTag nbttaglist2; - - if (!cmp.contains("HandDropChances", 10)) { - nbttaglist2 = new net.minecraft.nbt.ListTag(); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(0))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(0.0F)); - cmp.put("HandDropChances", nbttaglist2); - } - - if (!cmp.contains("ArmorDropChances", 10)) { - nbttaglist2 = new net.minecraft.nbt.ListTag(); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(1))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(2))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(3))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(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); - } - } - - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (!cmp.contains("tag", 10)) { - return cmp; - } else { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("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.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 { - - DataInspectorEntity() { - } - - 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.contains("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; - - 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (this.key.equals(new ResourceLocation(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) { - PaperweightDataConverters.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) { - PaperweightDataConverters.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.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"; - // Paper start - materials[409] = "minecraft:prismarine_shard"; - materials[410] = "minecraft:prismarine_crystals"; - materials[411] = "minecraft:rabbit"; - materials[412] = "minecraft:cooked_rabbit"; - materials[413] = "minecraft:rabbit_stew"; - materials[414] = "minecraft:rabbit_foot"; - materials[415] = "minecraft:rabbit_hide"; - materials[416] = "minecraft:armor_stand"; - materials[423] = "minecraft:mutton"; - materials[424] = "minecraft:cooked_mutton"; - materials[425] = "minecraft:banner"; - materials[426] = "minecraft:end_crystal"; - materials[427] = "minecraft:spruce_door"; - materials[428] = "minecraft:birch_door"; - materials[429] = "minecraft:jungle_door"; - materials[430] = "minecraft:acacia_door"; - materials[431] = "minecraft:dark_oak_door"; - materials[432] = "minecraft:chorus_fruit"; - materials[433] = "minecraft:chorus_fruit_popped"; - materials[434] = "minecraft:beetroot"; - materials[435] = "minecraft:beetroot_seeds"; - materials[436] = "minecraft:beetroot_soup"; - materials[437] = "minecraft:dragon_breath"; - materials[438] = "minecraft:splash_potion"; - materials[439] = "minecraft:spectral_arrow"; - materials[440] = "minecraft:tipped_arrow"; - materials[441] = "minecraft:lingering_potion"; - materials[442] = "minecraft:shield"; - materials[443] = "minecraft:elytra"; - materials[444] = "minecraft:spruce_boat"; - materials[445] = "minecraft:birch_boat"; - materials[446] = "minecraft:jungle_boat"; - materials[447] = "minecraft:acacia_boat"; - materials[448] = "minecraft:dark_oak_boat"; - materials[449] = "minecraft:totem_of_undying"; - materials[450] = "minecraft:shulker_shell"; - materials[452] = "minecraft:iron_nugget"; - materials[453] = "minecraft:knowledge_book"; - // Paper end - } - } - - 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.contains("tag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("BlockEntityTag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); - - if (nbttagcompound2.contains("Base", 99)) { - cmp.putShort("Damage", (short) (nbttagcompound2.getShort("Base") & 15)); - if (nbttagcompound1.contains("display", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound3 = nbttagcompound1.getCompound("display"); - - if (nbttagcompound3.contains("Lore", 9)) { - net.minecraft.nbt.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.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 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.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("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.contains("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.contains("SpawnPotentials", 9)) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); - - for (int i = 0; i < nbttaglist.size(); ++i) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist.getCompound(i); - - if (nbttagcompound2.contains("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.contains("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.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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("EntityHorse".equals(cmp.getString("id")) && !cmp.contains("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.contains("Facing", 99)) { - Direction enumdirection; - - if (cmp.contains("Direction", 99)) { - enumdirection = Direction.from2DDataValue(cmp.getByte("Direction")); - cmp.putInt("TileX", cmp.getInt("TileX") + enumdirection.getStepX()); - cmp.putInt("TileY", cmp.getInt("TileY") + enumdirection.getStepY()); - cmp.putInt("TileZ", cmp.getInt("TileZ") + enumdirection.getStepZ()); - cmp.remove("Direction"); - if (flag1 && cmp.contains("ItemRotation", 99)) { - cmp.putByte("ItemRotation", (byte) (cmp.getByte("ItemRotation") * 2)); - } - } else { - enumdirection = Direction.from2DDataValue(cmp.getByte("Dir")); - cmp.remove("Dir"); - } - - cmp.putByte("Facing", (byte) enumdirection.get2DDataValue()); - } - - 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) { - net.minecraft.nbt.ListTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - while (cmp.contains("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) { - net.minecraft.nbt.ListTag nbttaglist = new net.minecraft.nbt.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.contains("pages", 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("pages", 8); - - for (int i = 0; i < nbttaglist.size(); ++i) { - String s = nbttaglist.getString(i); - Component object = null; - - if (!"null".equals(s) && !StringUtil.isNullOrEmpty(s)) { - if ((s.charAt(0) != 34 || s.charAt(s.length() - 1) != 34) && (s.charAt(0) != 123 || s.charAt(s.length() - 1) != 125)) { - object = Component.literal(s); - } else { - try { - object = GsonHelper.fromJson(DataConverterSignText.a, s, Component.class, true); - if (object == null) { - object = Component.literal(""); - } - } catch (JsonParseException jsonparseexception) { - ; - } - - if (object == null) { - try { - object = Component.Serializer.fromJson(s); - } catch (JsonParseException jsonparseexception1) { - ; - } - } - - if (object == null) { - try { - object = Component.Serializer.fromJsonLenient(s); - } catch (JsonParseException jsonparseexception2) { - ; - } - } - - if (object == null) { - object = Component.literal(s); - } - } - } else { - object = Component.literal(""); - } - - nbttaglist.set(i, net.minecraft.nbt.StringTag.valueOf(Component.Serializer.toJson(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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 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 0: - default: - break; - - 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"); - } - - 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 0: - default: - cmp.putString("id", "Horse"); - break; - - 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"); - } - - 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.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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:shulker_box".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("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.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 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(PaperweightDataConverters.class); - - DataConverterBedBlock() { - } - - public int getDataVersion() { - return 1125; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - try { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); - int i = nbttagcompound1.getInt("xPos"); - int j = nbttagcompound1.getInt("zPos"); - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("TileEntities", 10); - net.minecraft.nbt.ListTag nbttaglist1 = nbttagcompound1.getList("Sections", 10); - - for (int k = 0; k < nbttaglist1.size(); ++k) { - net.minecraft.nbt.CompoundTag 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; - net.minecraft.nbt.CompoundTag nbttagcompound3 = new net.minecraft.nbt.CompoundTag(); - - nbttagcompound3.putString("id", "bed"); - nbttagcompound3.putInt("x", i1 + (i << 4)); - nbttagcompound3.putInt("y", j1 + (b0 << 4)); - nbttagcompound3.putInt("z", k1 + (j << 4)); - nbttaglist.add(nbttagcompound3); - } - } - } - } catch (Exception exception) { - DataConverterBedBlock.a.warn("Unable to datafix Bed blocks, level format may be missing tags."); - } - - return cmp; - } - } - - private static class DataConverterBedItem implements DataConverter { - - DataConverterBedItem() { - } - - public int getDataVersion() { - return 1125; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:bed".equals(cmp.getString("id")) && cmp.getShort("Damage") == 0) { - cmp.putShort("Damage", (short) DyeColor.RED.getId()); - } - - return cmp; - } - } - - private static class DataConverterSignText implements DataConverter { - - public static final Gson a = new GsonBuilder().registerTypeAdapter(Component.class, new JsonDeserializer() { - MutableComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { - if (jsonelement.isJsonPrimitive()) { - return Component.literal(jsonelement.getAsString()); - } else if (jsonelement.isJsonArray()) { - JsonArray jsonarray = jsonelement.getAsJsonArray(); - MutableComponent ichatbasecomponent = null; - Iterator iterator = jsonarray.iterator(); - - while (iterator.hasNext()) { - JsonElement jsonelement1 = (JsonElement) iterator.next(); - MutableComponent ichatbasecomponent1 = this.a(jsonelement1, jsonelement1.getClass(), jsondeserializationcontext); - - if (ichatbasecomponent == null) { - ichatbasecomponent = ichatbasecomponent1; - } else { - ichatbasecomponent.append(ichatbasecomponent1); - } - } - - return ichatbasecomponent; - } 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); - Component object = null; - - if (!"null".equals(s1) && !StringUtil.isNullOrEmpty(s1)) { - if ((s1.charAt(0) != 34 || s1.charAt(s1.length() - 1) != 34) && (s1.charAt(0) != 123 || s1.charAt(s1.length() - 1) != 125)) { - object = Component.literal(s1); - } else { - try { - object = GsonHelper.fromJson(DataConverterSignText.a, s1, Component.class, true); - if (object == null) { - object = Component.literal(""); - } - } catch (JsonParseException jsonparseexception) { - ; - } - - if (object == null) { - try { - object = Component.Serializer.fromJson(s1); - } catch (JsonParseException jsonparseexception1) { - ; - } - } - - if (object == null) { - try { - object = Component.Serializer.fromJsonLenient(s1); - } catch (JsonParseException jsonparseexception2) { - ; - } - } - - if (object == null) { - object = Component.literal(s1); - } - } - } else { - object = Component.literal(""); - } - - nbttagcompound.putString(s, Component.Serializer.toJson(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.contains("RootVehicle", 10)) { - net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - net.minecraft.nbt.ListTag nbttaglist; - int j; - net.minecraft.nbt.CompoundTag nbttagcompound1; - - if (cmp.contains("entities", 9)) { - nbttaglist = cmp.getList("entities", 10); - - for (j = 0; j < nbttaglist.size(); ++j) { - nbttagcompound1 = (net.minecraft.nbt.CompoundTag) 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 = (net.minecraft.nbt.CompoundTag) 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (cmp.contains("Level", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); - net.minecraft.nbt.ListTag 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, (net.minecraft.nbt.CompoundTag) 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, (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.contains("Passengers", 9)) { - net.minecraft.nbt.ListTag 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 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.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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (entityVillager.equals(new ResourceLocation(cmp.getString("id"))) && cmp.contains("Offers", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Offers"); - - if (nbttagcompound1.contains("Recipes", 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("Recipes", 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (tileEntityMobSpawner.equals(new ResourceLocation(cmp.getString("id")))) { - if (cmp.contains("SpawnPotentials", 9)) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightFakePlayer.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightFakePlayer.java deleted file mode 100644 index 87dca94f2..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightFakePlayer.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 General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1; - -import com.mojang.authlib.GameProfile; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ServerboundClientInformationPacket; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.stats.Stat; -import net.minecraft.world.MenuProvider; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.block.entity.SignBlockEntity; -import net.minecraft.world.phys.Vec3; -import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; - -import java.util.OptionalInt; -import java.util.UUID; - -class PaperweightFakePlayer extends ServerPlayer { - private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]"); - private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D); - - PaperweightFakePlayer(ServerLevel world) { - super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE); - } - - @Override - public Vec3 position() { - return ORIGIN; - } - - @Override - public void tick() { - } - - @Override - public void die(DamageSource damagesource) { - } - - @Override - public Entity changeDimension(ServerLevel worldserver, TeleportCause cause) { - return this; - } - - @Override - public OptionalInt openMenu(MenuProvider factory) { - return OptionalInt.empty(); - } - - @Override - public void updateOptions(ServerboundClientInformationPacket packet) { - } - - @Override - public void displayClientMessage(Component message, boolean actionBar) { - } - - @Override - public void awardStat(Stat stat, int amount) { - } - - @Override - public void awardStat(Stat stat) { - } - - @Override - public boolean isInvulnerableTo(DamageSource damageSource) { - return true; - } - - @Override - public void openTextEdit(SignBlockEntity sign, boolean front) { - } -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightWorldNativeAccess.java deleted file mode 100644 index ffca9e50d..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightWorldNativeAccess.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.world.block.BlockState; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.Tag; -import net.minecraft.server.level.FullChunkStatus; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.LevelChunk; -import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; -import org.bukkit.event.block.BlockPhysicsEvent; -import org.enginehub.linbus.tree.LinCompoundTag; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.util.Objects; - -public class PaperweightWorldNativeAccess implements WorldNativeAccess { - private static final int UPDATE = 1; - private static final int NOTIFY = 2; - - private final PaperweightAdapter adapter; - private final WeakReference world; - private SideEffectSet sideEffectSet; - - public PaperweightWorldNativeAccess(PaperweightAdapter adapter, WeakReference world) { - this.adapter = adapter; - this.world = world; - } - - private ServerLevel getWorld() { - return Objects.requireNonNull(world.get(), "The reference to the world was lost"); - } - - @Override - public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { - this.sideEffectSet = sideEffectSet; - } - - @Override - public LevelChunk getChunk(int x, int z) { - return getWorld().getChunk(x, z); - } - - @Override - public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) { - int stateId = BlockStateIdAccess.getBlockStateId(state); - return BlockStateIdAccess.isValidInternalId(stateId) - ? Block.stateById(stateId) - : ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk chunk, BlockPos position) { - return chunk.getBlockState(position); - } - - @Nullable - @Override - public net.minecraft.world.level.block.state.BlockState setBlockState(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState state) { - return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE)); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(net.minecraft.world.level.block.state.BlockState block, BlockPos position) { - return Block.updateFromNeighbourShapes(block, getWorld(), position); - } - - @Override - public BlockPos getPosition(int x, int y, int z) { - return new BlockPos(x, y, z); - } - - @Override - public void updateLightingForBlock(BlockPos position) { - getWorld().getChunkSource().getLightEngine().checkBlock(position); - } - - @Override - public boolean updateTileEntity(BlockPos position, LinCompoundTag tag) { - // We will assume that the tile entity was created for us - BlockEntity tileEntity = getWorld().getBlockEntity(position); - if (tileEntity == null) { - return false; - } - Tag nativeTag = adapter.fromNative(new CompoundTag(tag)); - PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity); - return true; - } - - @Override - public void notifyBlockUpdate(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { - if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { - getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY); - } - } - - @Override - public boolean isChunkTicking(LevelChunk chunk) { - return chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING); - } - - @Override - public void markBlockChanged(LevelChunk chunk, BlockPos position) { - if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { - getWorld().getChunkSource().blockChanged(position); - } - } - - @Override - public void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { - ServerLevel world = getWorld(); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - world.updateNeighborsAt(pos, oldState.getBlock()); - } else { - // When we don't want events, manually run the physics without them. - Block block = oldState.getBlock(); - fireNeighborChanged(pos, world, block, pos.west()); - fireNeighborChanged(pos, world, block, pos.east()); - fireNeighborChanged(pos, world, block, pos.below()); - fireNeighborChanged(pos, world, block, pos.above()); - fireNeighborChanged(pos, world, block, pos.north()); - fireNeighborChanged(pos, world, block, pos.south()); - } - if (newState.hasAnalogOutputSignal()) { - world.updateNeighbourForOutputSignal(pos, newState.getBlock()); - } - } - - @Override - public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { - ServerLevel world = getWorld(); - newState.onPlace(world, pos, oldState, false); - } - - // Not sure why neighborChanged is deprecated - @SuppressWarnings("deprecation") - private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { - world.getBlockState(neighborPos).neighborChanged(world, neighborPos, block, pos, false); - } - - @Override - public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) { - ServerLevel world = getWorld(); - // a == updateNeighbors - // b == updateDiagonalNeighbors - oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - CraftWorld craftWorld = world.getWorld(); - BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState)); - world.getCraftServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - } - newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit); - newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); - } - - @Override - public void onBlockStateChange(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { - getWorld().onBlockStateChange(pos, oldState, newState); - } - - @Override - public void flush() { - - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightBlockMaterial.java deleted file mode 100644 index 826874f57..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightBlockMaterial.java +++ /dev/null @@ -1,185 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; - -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.util.ReflectionUtil; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.world.registry.BlockMaterial; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.EmptyBlockGetter; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.EntityBlock; -import net.minecraft.world.level.block.LiquidBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.PushReaction; -import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; - -public class PaperweightBlockMaterial implements BlockMaterial { - - private final Block block; - private final BlockState blockState; - private final boolean isTranslucent; - private final CraftBlockData craftBlockData; - private final org.bukkit.Material craftMaterial; - private final int opacity; - private final CompoundTag tile; - - public PaperweightBlockMaterial(Block block) { - this(block, block.defaultBlockState()); - } - - public PaperweightBlockMaterial(Block block, BlockState blockState) { - this.block = block; - this.blockState = blockState; - this.craftBlockData = CraftBlockData.fromData(blockState); - this.craftMaterial = craftBlockData.getMaterial(); - BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, - Refraction.pickName("properties", "aN")); - this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo, - Refraction.pickName("canOcclude", "m") - ); - opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); - BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity( - BlockPos.ZERO, - blockState - ); - tile = tileEntity == null - ? null - : new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); - } - - public Block getBlock() { - return block; - } - - public BlockState getState() { - return blockState; - } - - public CraftBlockData getCraftBlockData() { - return craftBlockData; - } - - @Override - public boolean isAir() { - return blockState.isAir(); - } - - @Override - public boolean isFullCube() { - return craftMaterial.isOccluding(); - } - - @Override - public boolean isOpaque() { - return blockState.isOpaque(); - } - - @Override - public boolean isPowerSource() { - return blockState.isSignalSource(); - } - - @Override - public boolean isLiquid() { - // TODO: Better check ? - return block instanceof LiquidBlock; - } - - @Override - public boolean isSolid() { - // TODO: Replace - return blockState.isSolid(); - } - - @Override - public float getHardness() { - return craftBlockData.getState().destroySpeed; - } - - @Override - public float getResistance() { - return block.getExplosionResistance(); - } - - @Override - public float getSlipperiness() { - return block.getFriction(); - } - - @Override - public int getLightValue() { - return blockState.getLightEmission(); - } - - @Override - public int getLightOpacity() { - return opacity; - } - - @Override - public boolean isFragileWhenPushed() { - return blockState.getPistonPushReaction() == PushReaction.DESTROY; - } - - @Override - public boolean isUnpushable() { - return blockState.getPistonPushReaction() == PushReaction.BLOCK; - } - - @Override - public boolean isTicksRandomly() { - return block.isRandomlyTicking(blockState); - } - - @Override - public boolean isMovementBlocker() { - return craftMaterial.isSolid(); - } - - @Override - public boolean isBurnable() { - return craftMaterial.isBurnable(); - } - - @Override - public boolean isToolRequired() { - // Removed in 1.16.1, this is not present in higher versions - return false; - } - - @Override - public boolean isReplacedDuringPlacement() { - return blockState.canBeReplaced(); - } - - @Override - public boolean isTranslucent() { - return isTranslucent; - } - - @Override - public boolean hasContainer() { - return block instanceof EntityBlock; - } - - @Override - public boolean isTile() { - return block instanceof EntityBlock; - } - - @Override - public CompoundTag getDefaultTile() { - return tile; - } - - @Override - public int getMapColor() { - // rgb field - return block.defaultMapColor().col; - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweAdapter.java deleted file mode 100644 index 7fd24c7d9..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweAdapter.java +++ /dev/null @@ -1,614 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; - -import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; -import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.entity.LazyBaseEntity; -import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IBatchProcessor; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; -import com.fastasyncworldedit.core.util.NbtUtils; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1.PaperweightAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.regen.PaperweightRegen; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; -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.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.world.RegenOptions; -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.block.BlockType; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import com.sk89q.worldedit.world.entity.EntityType; -import com.sk89q.worldedit.world.item.ItemType; -import com.sk89q.worldedit.world.registry.BlockMaterial; -import io.papermc.lib.PaperLib; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Registry; -import net.minecraft.core.WritableRegistry; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.util.StringRepresentable; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.DirectionProperty; -import net.minecraft.world.level.chunk.LevelChunk; -import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.World; -import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_20_R1.CraftServer; -import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_20_R1.util.CraftNamespacedKey; -import org.bukkit.entity.Player; -import org.enginehub.linbus.tree.LinCompoundTag; -import org.enginehub.linbus.tree.LinStringTag; -import org.enginehub.linbus.tree.LinTag; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.OptionalInt; -import java.util.Set; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static net.minecraft.core.registries.Registries.BIOME; - -public final class PaperweightFaweAdapter extends FaweAdapter { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; - - static { - try { - CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE = ChunkHolder.class.getDeclaredMethod("wasAccessibleSinceLastSave"); - } catch (NoSuchMethodException ignored) { // may not be present in newer paper versions - } - } - - private final PaperweightAdapter parent; - // ------------------------------------------------------------------------ - // Code that may break between versions of Minecraft - // ------------------------------------------------------------------------ - private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil(); - private char[] ibdToStateOrdinal = null; - private int[] ordinalToIbdID = null; - private boolean initialised = false; - private Map>> allBlockProperties = null; - - public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { - this.parent = new PaperweightAdapter(); - } - - @Nullable - private static String getEntityId(Entity entity) { - ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType()); - return resourceLocation == null ? null : resourceLocation.toString(); - } - - @Override - public BukkitImplAdapter getParent() { - return parent; - } - - private synchronized boolean init() { - if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) { - return false; - } - ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size - ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size - for (int i = 0; i < ibdToStateOrdinal.length; i++) { - BlockState blockState = BlockTypesCache.states[i]; - PaperweightBlockMaterial material = (PaperweightBlockMaterial) blockState.getMaterial(); - int id = Block.BLOCK_STATE_REGISTRY.getId(material.getState()); - char ordinal = blockState.getOrdinalChar(); - ibdToStateOrdinal[id] = ordinal; - ordinalToIbdID[ordinal] = id; - } - Map>> properties = new HashMap<>(); - try { - for (Field field : BlockStateProperties.class.getDeclaredFields()) { - Object obj = field.get(null); - if (!(obj instanceof net.minecraft.world.level.block.state.properties.Property state)) { - continue; - } - Property property; - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - property = new BooleanProperty( - state.getName(), - (List) ImmutableList.copyOf(state.getPossibleValues()) - ); - } else if (state instanceof DirectionProperty) { - property = new DirectionalProperty( - state.getName(), - state - .getPossibleValues() - .stream() - .map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase())) - .collect(Collectors.toList()) - ); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - property = new EnumProperty( - state.getName(), - state - .getPossibleValues() - .stream() - .map(e -> ((StringRepresentable) e).getSerializedName()) - .collect(Collectors.toList()) - ); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - property = new IntegerProperty( - state.getName(), - (List) ImmutableList.copyOf(state.getPossibleValues()) - ); - } else { - throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state - .getClass() - .getSimpleName()); - } - properties.compute(property.getName().toLowerCase(Locale.ROOT), (k, v) -> { - if (v == null) { - v = new ArrayList<>(Collections.singletonList(property)); - } else { - v.add(property); - } - return v; - }); - } - } catch (IllegalAccessException e) { - e.printStackTrace(); - } finally { - allBlockProperties = ImmutableMap.copyOf(properties); - } - initialised = true; - return true; - } - - @Override - public BlockMaterial getMaterial(BlockType blockType) { - Block block = getBlock(blockType); - return new PaperweightBlockMaterial(block); - } - - @Override - public synchronized BlockMaterial getMaterial(BlockState state) { - net.minecraft.world.level.block.state.BlockState blockState = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState(); - return new PaperweightBlockMaterial(blockState.getBlock(), blockState); - } - - public Block getBlock(BlockType blockType) { - return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK) - .get(new ResourceLocation(blockType.getNamespace(), blockType.getResource())); - } - - @Deprecated - @Override - public BlockState getBlock(Location location) { - Preconditions.checkNotNull(location); - - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - final ServerLevel handle = getServerLevel(location.getWorld()); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - BlockState state = adapt(blockData); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - return state; - } - - @Override - public BaseBlock getFullBlock(final Location location) { - Preconditions.checkNotNull(location); - - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = getServerLevel(location.getWorld()); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - BlockState state = adapt(blockData); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - if (state.getBlockType().getMaterial().hasContainer()) { - - // Read the NBT data - BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); - if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); - return state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); - } - } - - return state.toBaseBlock(); - } - - @Override - public Set getSupportedSideEffects() { - return SideEffectSet.defaults().getSideEffectsToApply(); - } - - @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); - } - - @Override - public BaseEntity getEntity(org.bukkit.entity.Entity entity) { - Preconditions.checkNotNull(entity); - - CraftEntity craftEntity = ((CraftEntity) entity); - Entity mcEntity = craftEntity.getHandle(); - - String id = getEntityId(mcEntity); - - if (id != null) { - EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); - Supplier saveTag = () -> { - final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(mcEntity, minecraftTag); - //add Id for AbstractChangeSet to work - final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag); - final Map> tags = NbtUtils.getLinCompoundTagValues(tag); - tags.put("Id", LinStringTag.of(id)); - return LinCompoundTag.of(tags); - }; - return new LazyBaseEntity(type, saveTag); - } else { - return null; - } - } - - @Override - public Component getRichBlockName(BlockType blockType) { - return parent.getRichBlockName(blockType); - } - - @Override - public Component getRichItemName(ItemType itemType) { - return parent.getRichItemName(itemType); - } - - @Override - public Component getRichItemName(BaseItemStack itemStack) { - return parent.getRichItemName(itemStack); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockState state) { - PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); - net.minecraft.world.level.block.state.BlockState mcState = material.getCraftBlockData().getState(); - return OptionalInt.of(Block.BLOCK_STATE_REGISTRY.getId(mcState)); - } - - @Override - public BlockState adapt(BlockData blockData) { - CraftBlockData cbd = ((CraftBlockData) blockData); - net.minecraft.world.level.block.state.BlockState ibd = cbd.getState(); - return adapt(ibd); - } - - public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) { - return BlockTypesCache.states[adaptToChar(blockState)]; - } - - public char adaptToChar(net.minecraft.world.level.block.state.BlockState blockState) { - int id = Block.BLOCK_STATE_REGISTRY.getId(blockState); - if (initialised) { - return ibdToStateOrdinal[id]; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - try { - init(); - return ibdToStateOrdinal[id]; - } catch (ArrayIndexOutOfBoundsException e1) { - LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!", - blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1 - ); - return BlockTypesCache.ReservedIDs.AIR; - } - } - } - - public char ibdIDToOrdinal(int id) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - init(); - return ibdToStateOrdinal[id]; - } - } - - @Override - public char[] getIbdToStateOrdinal() { - if (initialised) { - return ibdToStateOrdinal; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal; - } - init(); - return ibdToStateOrdinal; - } - } - - public int ordinalToIbdID(char ordinal) { - if (initialised) { - return ordinalToIbdID[ordinal]; - } - synchronized (this) { - if (initialised) { - return ordinalToIbdID[ordinal]; - } - init(); - return ordinalToIbdID[ordinal]; - } - } - - @Override - public int[] getOrdinalToIbdID() { - if (initialised) { - return ordinalToIbdID; - } - synchronized (this) { - if (initialised) { - return ordinalToIbdID; - } - init(); - return ordinalToIbdID; - } - } - - @Override - public > BlockData adapt(B state) { - PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); - return material.getCraftBlockData(); - } - - @Override - public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { - ServerLevel nmsWorld = getServerLevel(world); - ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); - if (map != null && wasAccessibleSinceLastSave(map)) { - boolean flag = false; - // PlayerChunk.d players = map.players; - Stream stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag) - */ Stream.empty(); - - ServerPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle(); - stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer) - .forEach(entityPlayer -> { - synchronized (chunkPacket) { - ClientboundLevelChunkWithLightPacket nmsPacket = (ClientboundLevelChunkWithLightPacket) chunkPacket.getNativePacket(); - if (nmsPacket == null) { - nmsPacket = mapUtil.create(this, chunkPacket); - chunkPacket.setNativePacket(nmsPacket); - } - try { - FaweCache.INSTANCE.CHUNK_FLAG.get().set(true); - entityPlayer.connection.send(nmsPacket); - } finally { - FaweCache.INSTANCE.CHUNK_FLAG.get().set(false); - } - } - }); - } - } - - @Override - public Map> getProperties(BlockType blockType) { - return getParent().getProperties(blockType); - } - - @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) { - int internalId = BlockStateIdAccess.getBlockStateId(blockState); - net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); - return blockState1.hasPostProcess( - getServerLevel(world), - new BlockPos(blockVector3.x(), blockVector3.y(), blockVector3.z()) - ); - } - - @Override - public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { - ItemStack stack = new ItemStack( - DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM) - .get(ResourceLocation.tryParse(baseItemStack.getType().id())), - baseItemStack.getAmount() - ); - stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()))); - return CraftItemStack.asCraftMirror(stack); - } - - @Override - protected void preCaptureStates(final ServerLevel serverLevel) { - serverLevel.captureTreeGeneration = true; - serverLevel.captureBlockStates = true; - } - - @Override - protected List getCapturedBlockStatesCopy(final ServerLevel serverLevel) { - return new ArrayList<>(serverLevel.capturedBlockStates.values()); - } - - @Override - protected void postCaptureBlockStates(final ServerLevel serverLevel) { - serverLevel.captureBlockStates = false; - serverLevel.captureTreeGeneration = false; - serverLevel.capturedBlockStates.clear(); - } - - @Override - protected ServerLevel getServerLevel(final World world) { - return ((CraftWorld) world).getHandle(); - } - - @Override - public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { - final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); - final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); - weStack.setNbt(((LinCompoundTag) toNativeLin(nmsStack.getTag()))); - return weStack; - } - - @Override - public Tag toNative(net.minecraft.nbt.Tag foreign) { - return parent.toNative(foreign); - } - - @Override - public net.minecraft.nbt.Tag fromNative(Tag foreign) { - if (foreign instanceof PaperweightLazyCompoundTag) { - return ((PaperweightLazyCompoundTag) foreign).get(); - } - return parent.fromNative(foreign); - } - - @Override - public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { - return new PaperweightRegen(bukkitWorld, region, target, options).regenerate(); - } - - @Override - public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { - return new PaperweightGetBlocks(world, chunkX, chunkZ); - } - - @Override - public int getInternalBiomeId(BiomeType biomeType) { - final Registry registry = MinecraftServer - .getServer() - .registryAccess() - .registryOrThrow(BIOME); - ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.id()); - Biome biome = registry.get(resourceLocation); - return registry.getId(biome); - } - - @Override - public Iterable getRegisteredBiomes() { - WritableRegistry biomeRegistry = (WritableRegistry) ((CraftServer) Bukkit.getServer()) - .getServer() - .registryAccess() - .registryOrThrow(BIOME); - List keys = biomeRegistry.stream() - .map(biomeRegistry::getKey).filter(Objects::nonNull).toList(); - List namespacedKeys = new ArrayList<>(); - for (ResourceLocation key : keys) { - try { - namespacedKeys.add(CraftNamespacedKey.fromMinecraft(key)); - } catch (IllegalArgumentException e) { - LOGGER.error("Error converting biome key {}", key.toString(), e); - } - } - return namespacedKeys; - } - - @Override - public RelighterFactory getRelighterFactory() { - if (PaperLib.isPaper()) { - return new PaperweightStarlightRelighterFactory(); - } else { - return new NMSRelighterFactory(); - } - } - - @Override - public Map>> getAllProperties() { - if (initialised) { - return allBlockProperties; - } - synchronized (this) { - if (initialised) { - return allBlockProperties; - } - init(); - return allBlockProperties; - } - } - - @Override - public IBatchProcessor getTickingPostProcessor() { - return new PaperweightPostProcessor(); - } - - private boolean wasAccessibleSinceLastSave(ChunkHolder holder) { - if (!PaperLib.isPaper() || !PaperweightPlatformAdapter.POST_CHUNK_REWRITE) { - try { - return (boolean) CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE.invoke(holder); - } catch (IllegalAccessException | InvocationTargetException ignored) { - // fall-through - } - } - // Papers new chunk system has no related replacement - therefor we assume true. - return true; - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweWorldNativeAccess.java deleted file mode 100644 index b06d962a0..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweWorldNativeAccess.java +++ /dev/null @@ -1,292 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; - -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.math.IntPair; -import com.fastasyncworldedit.core.util.TaskManager; -import com.fastasyncworldedit.core.util.task.RunnableVal; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.world.block.BlockState; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.FullChunkStatus; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.LevelChunk; -import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; -import org.bukkit.event.block.BlockPhysicsEvent; -import org.enginehub.linbus.tree.LinCompoundTag; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.util.Collections; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; - -public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess { - - private static final int UPDATE = 1; - private static final int NOTIFY = 2; - private static final Direction[] NEIGHBOUR_ORDER = { - Direction.EAST, - Direction.WEST, - Direction.DOWN, - Direction.UP, - Direction.NORTH, - Direction.SOUTH - }; - private final PaperweightFaweAdapter paperweightFaweAdapter; - private final WeakReference level; - private final AtomicInteger lastTick; - private final Set cachedChanges = new HashSet<>(); - private final Set cachedChunksToSend = new HashSet<>(); - private SideEffectSet sideEffectSet; - - public PaperweightFaweWorldNativeAccess(PaperweightFaweAdapter paperweightFaweAdapter, WeakReference level) { - this.paperweightFaweAdapter = paperweightFaweAdapter; - this.level = level; - // Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging. - // - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway. - this.lastTick = new AtomicInteger(MinecraftServer.currentTick); - } - - private Level getLevel() { - return Objects.requireNonNull(level.get(), "The reference to the world was lost"); - } - - @Override - public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { - this.sideEffectSet = sideEffectSet; - } - - @Override - public LevelChunk getChunk(int x, int z) { - return getLevel().getChunk(x, z); - } - - @Override - public net.minecraft.world.level.block.state.BlockState toNative(BlockState blockState) { - int stateId = paperweightFaweAdapter.ordinalToIbdID(blockState.getOrdinalChar()); - return BlockStateIdAccess.isValidInternalId(stateId) - ? Block.stateById(stateId) - : ((CraftBlockData) BukkitAdapter.adapt(blockState)).getState(); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk levelChunk, BlockPos blockPos) { - return levelChunk.getBlockState(blockPos); - } - - @Nullable - @Override - public synchronized net.minecraft.world.level.block.state.BlockState setBlockState( - LevelChunk levelChunk, BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState blockState - ) { - int currentTick = MinecraftServer.currentTick; - if (Fawe.isMainThread()) { - return levelChunk.setBlockState(blockPos, blockState, - this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE) - ); - } - // Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( ) - cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState)); - cachedChunksToSend.add(new IntPair(levelChunk.locX, levelChunk.locZ)); - boolean nextTick = lastTick.get() > currentTick; - if (nextTick || cachedChanges.size() >= 1024) { - if (nextTick) { - lastTick.set(currentTick); - } - flushAsync(nextTick); - } - return blockState; - } - - @Override - public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition( - net.minecraft.world.level.block.state.BlockState blockState, - BlockPos blockPos - ) { - return Block.updateFromNeighbourShapes(blockState, getLevel(), blockPos); - } - - @Override - public BlockPos getPosition(int x, int y, int z) { - return new BlockPos(x, y, z); - } - - @Override - public void updateLightingForBlock(BlockPos blockPos) { - getLevel().getChunkSource().getLightEngine().checkBlock(blockPos); - } - - @Override - public boolean updateTileEntity(BlockPos blockPos, LinCompoundTag tag) { - // We will assume that the tile entity was created for us, - // though we do not do this on the other versions - BlockEntity blockEntity = getLevel().getBlockEntity(blockPos); - if (blockEntity == null) { - return false; - } - net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeLin(tag); - blockEntity.load((CompoundTag) nativeTag); - return true; - } - - @Override - public void notifyBlockUpdate( - LevelChunk levelChunk, BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { - getLevel().sendBlockUpdated(blockPos, oldState, newState, UPDATE | NOTIFY); - } - } - - @Override - public boolean isChunkTicking(LevelChunk levelChunk) { - return levelChunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING); - } - - @Override - public void markBlockChanged(LevelChunk levelChunk, BlockPos blockPos) { - if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { - ((ServerChunkCache) getLevel().getChunkSource()).blockChanged(blockPos); - } - } - - @Override - public void notifyNeighbors( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - Level level = getLevel(); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - level.blockUpdated(blockPos, oldState.getBlock()); - } else { - // When we don't want events, manually run the physics without them. - // Un-nest neighbour updating - for (Direction direction : NEIGHBOUR_ORDER) { - BlockPos shifted = blockPos.relative(direction); - level.getBlockState(shifted).neighborChanged(level, shifted, oldState.getBlock(), blockPos, false); - } - } - if (newState.hasAnalogOutputSignal()) { - level.updateNeighbourForOutputSignal(blockPos, newState.getBlock()); - } - } - - @Override - public void updateNeighbors( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState, - int recursionLimit - ) { - Level level = getLevel(); - // a == updateNeighbors - // b == updateDiagonalNeighbors - oldState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - CraftWorld craftWorld = level.getWorld(); - if (craftWorld != null) { - BlockPhysicsEvent event = new BlockPhysicsEvent( - craftWorld.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()), - CraftBlockData.fromData(newState) - ); - level.getCraftServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - } - } - newState.triggerEvent(level, blockPos, NOTIFY, recursionLimit); - newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); - } - - @Override - public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { - Level world = getLevel(); - newState.onPlace(world, pos, oldState, false); - } - - @Override - public void onBlockStateChange( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - getLevel().onBlockStateChange(blockPos, oldState, newState); - } - - private synchronized void flushAsync(final boolean sendChunks) { - final Set changes = Set.copyOf(cachedChanges); - cachedChanges.clear(); - final Set toSend; - if (sendChunks) { - toSend = Set.copyOf(cachedChunksToSend); - cachedChunksToSend.clear(); - } else { - toSend = Collections.emptySet(); - } - RunnableVal runnableVal = new RunnableVal<>() { - @Override - public void run(Object value) { - changes.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, - sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) - )); - if (!sendChunks) { - return; - } - for (IntPair chunk : toSend) { - PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z()); - } - } - }; - TaskManager.taskManager().async(() -> TaskManager.taskManager().sync(runnableVal)); - } - - @Override - public synchronized void flush() { - RunnableVal runnableVal = new RunnableVal<>() { - @Override - public void run(Object value) { - cachedChanges.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, - sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) - )); - for (IntPair chunk : cachedChunksToSend) { - PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z()); - } - } - }; - if (Fawe.isMainThread()) { - runnableVal.run(); - } else { - TaskManager.taskManager().sync(runnableVal); - } - cachedChanges.clear(); - cachedChunksToSend.clear(); - } - - private record CachedChange( - LevelChunk levelChunk, - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState blockState - ) { - - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java deleted file mode 100644 index 91bcf0e92..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java +++ /dev/null @@ -1,1184 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; - -import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; -import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; -import com.fastasyncworldedit.core.math.BitArrayUnstretched; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.fastasyncworldedit.core.queue.implementation.QueueHandler; -import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.collection.AdaptedMap; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.internal.Constants; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.BiomeTypes; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import io.papermc.lib.PaperLib; -import io.papermc.paper.event.block.BeaconDeactivatedEvent; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.IdMap; -import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; -import net.minecraft.nbt.IntTag; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.util.BitStorage; -import net.minecraft.util.ZeroBitStorage; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.entity.BeaconBlockEntity; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.HashMapPalette; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.LinearPalette; -import net.minecraft.world.level.chunk.Palette; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.level.lighting.LevelLightEngine; -import org.apache.logging.log4j.Logger; -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlock; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import javax.annotation.Nonnull; -import java.util.AbstractSet; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Future; -import java.util.concurrent.Semaphore; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static net.minecraft.core.registries.Registries.BIOME; - -public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private static final Function posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); - private static final Function nmsTile2We = - tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); - private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin - .getInstance() - .getBukkitImplAdapter()); - private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); - private final ReentrantLock callLock = new ReentrantLock(); - private final ServerLevel serverLevel; - private final int chunkX; - private final int chunkZ; - private final int minHeight; - private final int maxHeight; - private final int minSectionPosition; - private final int maxSectionPosition; - private final Registry biomeRegistry; - private final IdMap> biomeHolderIdMap; - private final ConcurrentHashMap copies = new ConcurrentHashMap<>(); - private final Object sendLock = new Object(); - private LevelChunkSection[] sections; - private LevelChunk levelChunk; - private DataLayer[] blockLight; - private DataLayer[] skyLight; - private boolean createCopy = false; - private boolean forceLoadSections = true; - private boolean lightUpdate = false; - private int copyKey = 0; - - public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { - this(((CraftWorld) world).getHandle(), chunkX, chunkZ); - } - - public PaperweightGetBlocks(ServerLevel serverLevel, int chunkX, int chunkZ) { - super(serverLevel.getMinBuildHeight() >> 4, (serverLevel.getMaxBuildHeight() - 1) >> 4); - this.serverLevel = serverLevel; - this.chunkX = chunkX; - this.chunkZ = chunkZ; - this.minHeight = serverLevel.getMinBuildHeight(); - this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. - this.minSectionPosition = minHeight >> 4; - this.maxSectionPosition = maxHeight >> 4; - this.skyLight = new DataLayer[getSectionCount()]; - this.blockLight = new DataLayer[getSectionCount()]; - this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME); - this.biomeHolderIdMap = biomeRegistry.asHolderIdMap(); - } - - public int getChunkX() { - return chunkX; - } - - public int getChunkZ() { - return chunkZ; - } - - @Override - public boolean isCreateCopy() { - return createCopy; - } - - @Override - public int setCreateCopy(boolean createCopy) { - if (!callLock.isHeldByCurrentThread()) { - throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); - } - this.createCopy = createCopy; - // Increment regardless of whether copy will be created or not to return null from getCopy() - return ++this.copyKey; - } - - @Override - public IChunkGet getCopy(final int key) { - return copies.remove(key); - } - - @Override - public void lockCall() { - this.callLock.lock(); - } - - @Override - public void unlockCall() { - this.callLock.unlock(); - } - - @Override - public void setLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { - if (light != null) { - lightUpdate = true; - try { - fillLightNibble(light, LightLayer.BLOCK, minSectionPosition, maxSectionPosition); - } catch (Throwable e) { - e.printStackTrace(); - } - } - } - - @Override - public void setSkyLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { - if (light != null) { - lightUpdate = true; - try { - fillLightNibble(light, LightLayer.SKY, minSectionPosition, maxSectionPosition); - } catch (Throwable e) { - e.printStackTrace(); - } - } - } - - @Override - public void setHeightmapToGet(HeightMapType type, int[] data) { - // height + 1 to match server internal - BitArrayUnstretched bitArray = new BitArrayUnstretched(MathMan.log2nlz(getChunk().getHeight() + 1), 256); - bitArray.fromRaw(data); - Heightmap.Types nativeType = Heightmap.Types.valueOf(type.name()); - Heightmap heightMap = getChunk().heightmaps.get(nativeType); - heightMap.setRawData(getChunk(), nativeType, bitArray.getData()); - } - - @Override - public int getMaxY() { - return maxHeight; - } - - @Override - public int getMinY() { - return minHeight; - } - - @Override - public BiomeType getBiomeType(int x, int y, int z) { - LevelChunkSection section = getSections(false)[(y >> 4) - getMinSectionPosition()]; - Holder biomes = section.getNoiseBiome(x >> 2, (y & 15) >> 2, z >> 2); - return PaperweightPlatformAdapter.adapt(biomes, serverLevel); - } - - @Override - public void removeSectionLighting(int layer, boolean sky) { - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.BLOCK).getDataLayerData( - sectionPos); - if (dataLayer != null) { - lightUpdate = true; - synchronized (dataLayer) { - byte[] bytes = dataLayer.getData(); - Arrays.fill(bytes, (byte) 0); - } - } - if (sky) { - SectionPos sectionPos1 = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer1 = serverLevel - .getChunkSource() - .getLightEngine() - .getLayerListener(LightLayer.SKY) - .getDataLayerData(sectionPos1); - if (dataLayer1 != null) { - lightUpdate = true; - synchronized (dataLayer1) { - byte[] bytes = dataLayer1.getData(); - Arrays.fill(bytes, (byte) 0); - } - } - } - } - - @Override - public CompoundTag getTile(int x, int y, int z) { - BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( - chunkX << 4), y, (z & 15) + ( - chunkZ << 4))); - if (blockEntity == null) { - return null; - } - return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)); - } - - @Override - public Map getTiles() { - Map nmsTiles = getChunk().getBlockEntities(); - if (nmsTiles.isEmpty()) { - return Collections.emptyMap(); - } - return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); - } - - @Override - public int getSkyLight(int x, int y, int z) { - int layer = y >> 4; - int alayer = layer - getMinSectionPosition(); - if (skyLight[alayer] == null) { - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = - serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.SKY).getDataLayerData(sectionPos); - // If the server hasn't generated the section's NibbleArray yet, it will be null - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. - Arrays.fill(LAYER_COUNT, (byte) 15); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( - LightLayer.BLOCK, - sectionPos, - dataLayer - ); - } - skyLight[alayer] = dataLayer; - } - return skyLight[alayer].get(x & 15, y & 15, z & 15); - } - - @Override - public int getEmittedLight(int x, int y, int z) { - int layer = y >> 4; - int alayer = layer - getMinSectionPosition(); - if (blockLight[alayer] == null) { - serverLevel.getRawBrightness(new BlockPos(1, 1, 1), 5); - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = serverLevel - .getChunkSource() - .getLightEngine() - .getLayerListener(LightLayer.BLOCK) - .getDataLayerData(sectionPos); - // If the server hasn't generated the section's DataLayer yet, it will be null - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. - Arrays.fill(LAYER_COUNT, (byte) 15); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos, - dataLayer - ); - } - blockLight[alayer] = dataLayer; - } - return blockLight[alayer].get(x & 15, y & 15, z & 15); - } - - @Override - public int[] getHeightMap(HeightMapType type) { - long[] longArray = getChunk().heightmaps.get(Heightmap.Types.valueOf(type.name())).getRawData(); - BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256, longArray); - return bitArray.toRaw(new int[256]); - } - - @Override - public CompoundTag getEntity(UUID uuid) { - Entity entity = serverLevel.getEntity(uuid); - if (entity != null) { - org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); - return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); - } - for (CompoundTag tag : getEntities()) { - if (uuid.equals(tag.getUUID())) { - return tag; - } - } - return null; - } - - @Override - public Set getEntities() { - ensureLoaded(serverLevel, chunkX, chunkZ); - List entities = PaperweightPlatformAdapter.getEntities(getChunk()); - if (entities.isEmpty()) { - return Collections.emptySet(); - } - int size = entities.size(); - return new AbstractSet<>() { - @Override - public int size() { - return size; - } - - @Override - public boolean isEmpty() { - return false; - } - - @Override - public boolean contains(Object get) { - if (!(get instanceof CompoundTag getTag)) { - return false; - } - UUID getUUID = getTag.getUUID(); - for (Entity entity : entities) { - UUID uuid = entity.getUUID(); - if (uuid.equals(getUUID)) { - return true; - } - } - return false; - } - - @Nonnull - @Override - public Iterator iterator() { - Iterable result = entities.stream().map(input -> { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(input, tag); - return (CompoundTag) adapter.toNative(tag); - }).collect(Collectors.toList()); - return result.iterator(); - } - }; - } - - private void removeEntity(Entity entity) { - entity.discard(); - } - - public LevelChunk ensureLoaded(ServerLevel nmsWorld, int chunkX, int chunkZ) { - return PaperweightPlatformAdapter.ensureLoaded(nmsWorld, chunkX, chunkZ); - } - - @Override - @SuppressWarnings("rawtypes") - public synchronized > T call(IChunkSet set, Runnable finalizer) { - if (!callLock.isHeldByCurrentThread()) { - throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked."); - } - forceLoadSections = false; - PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; - if (createCopy) { - if (copies.containsKey(copyKey)) { - throw new IllegalStateException("Copy key already used."); - } - copies.put(copyKey, copy); - } - try { - ServerLevel nmsWorld = serverLevel; - LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); - - // Remove existing tiles. Create a copy so that we can remove blocks - Map chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); - List beacons = null; - if (!chunkTiles.isEmpty()) { - for (Map.Entry entry : chunkTiles.entrySet()) { - final BlockPos pos = entry.getKey(); - final int lx = pos.getX() & 15; - final int ly = pos.getY(); - final int lz = pos.getZ() & 15; - final int layer = ly >> 4; - if (!set.hasSection(layer)) { - continue; - } - - int ordinal = set.getBlock(lx, ly, lz).getOrdinal(); - if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) { - BlockEntity tile = entry.getValue(); - if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) { - if (beacons == null) { - beacons = new ArrayList<>(); - } - beacons.add(tile); - PaperweightPlatformAdapter.removeBeacon(tile, nmsChunk); - continue; - } - nmsChunk.removeBlockEntity(tile.getBlockPos()); - if (createCopy) { - copy.storeTile(tile); - } - } - } - } - final BiomeType[][] biomes = set.getBiomes(); - - int bitMask = 0; - synchronized (nmsChunk) { - LevelChunkSection[] levelChunkSections = nmsChunk.getSections(); - - for (int layerNo = getMinSectionPosition(); layerNo <= getMaxSectionPosition(); layerNo++) { - - int getSectionIndex = layerNo - getMinSectionPosition(); - int setSectionIndex = layerNo - set.getMinSectionPosition(); - - if (!set.hasSection(layerNo)) { - // No blocks, but might be biomes present. Handle this lazily. - if (biomes == null) { - continue; - } - if (layerNo < set.getMinSectionPosition() || layerNo > set.getMaxSectionPosition()) { - continue; - } - if (biomes[setSectionIndex] != null) { - synchronized (super.sectionLocks[getSectionIndex]) { - LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; - if (createCopy && existingSection != null) { - copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); - } - - if (existingSection == null) { - PalettedContainer> biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer( - biomes[setSectionIndex], - biomeHolderIdMap - ); - LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection( - layerNo, - new char[4096], - adapter, - biomeRegistry, - biomeData - ); - if (PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - null, - newSection, - getSectionIndex - )) { - updateGet(nmsChunk, levelChunkSections, newSection, new char[4096], getSectionIndex); - continue; - } else { - existingSection = levelChunkSections[getSectionIndex]; - if (existingSection == null) { - LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - getSectionIndex - ); - continue; - } - } - } else { - PalettedContainer> paletteBiomes = setBiomesToPalettedContainer( - biomes, - setSectionIndex, - existingSection.getBiomes() - ); - if (paletteBiomes != null) { - PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes); - } - } - } - } - continue; - } - - bitMask |= 1 << getSectionIndex; - - // setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to - // this chunk GET when #updateGet is called. Future dords, please listen this time. - char[] tmp = set.load(layerNo); - char[] setArr = new char[tmp.length]; - System.arraycopy(tmp, 0, setArr, 0, tmp.length); - - // synchronise on internal section to avoid circular locking with a continuing edit if the chunk was - // submitted to keep loaded internal chunks to queue target size. - synchronized (super.sectionLocks[getSectionIndex]) { - - LevelChunkSection newSection; - LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; - // Don't attempt to tick section whilst we're editing - if (existingSection != null) { - PaperweightPlatformAdapter.clearCounts(existingSection); - if (PaperLib.isPaper()) { - existingSection.tickingList.clear(); - } - } - - if (createCopy) { - char[] tmpLoad = loadPrivately(layerNo); - char[] copyArr = new char[4096]; - System.arraycopy(tmpLoad, 0, copyArr, 0, 4096); - copy.storeSection(getSectionIndex, copyArr); - if (biomes != null && existingSection != null) { - copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); - } - } - - if (existingSection == null) { - PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( - biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), - PalettedContainer.Strategy.SECTION_BIOMES - ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); - newSection = PaperweightPlatformAdapter.newChunkSection( - layerNo, - setArr, - adapter, - biomeRegistry, - biomeData - ); - if (PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - null, - newSection, - getSectionIndex - )) { - updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); - continue; - } else { - existingSection = levelChunkSections[getSectionIndex]; - if (existingSection == null) { - LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - getSectionIndex - ); - continue; - } - } - } - - //ensure that the server doesn't try to tick the chunksection while we're editing it. (Again) - PaperweightPlatformAdapter.clearCounts(existingSection); - if (PaperLib.isPaper()) { - existingSection.tickingList.clear(); - } - DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); - - // Synchronize to prevent further acquisitions - synchronized (lock) { - lock.acquire(); // Wait until we have the lock - lock.release(); - try { - sectionLock.writeLock().lock(); - if (this.getChunk() != nmsChunk) { - this.levelChunk = nmsChunk; - this.sections = null; - this.reset(); - } else if (existingSection != getSections(false)[getSectionIndex]) { - this.sections[getSectionIndex] = existingSection; - this.reset(); - } else if (!Arrays.equals( - update(getSectionIndex, new char[4096], true), - loadPrivately(layerNo) - )) { - this.reset(layerNo); - /*} else if (lock.isModified()) { - this.reset(layerNo);*/ - } - } finally { - sectionLock.writeLock().unlock(); - } - - PalettedContainer> biomeData = setBiomesToPalettedContainer( - biomes, - setSectionIndex, - existingSection.getBiomes() - ); - - newSection = PaperweightPlatformAdapter.newChunkSection( - layerNo, - this::loadPrivately, - setArr, - adapter, - biomeRegistry, - biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() - ); - if (!PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - existingSection, - newSection, - getSectionIndex - )) { - LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - getSectionIndex - ); - } else { - updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); - } - } - } - } - - Map heightMaps = set.getHeightMaps(); - for (Map.Entry entry : heightMaps.entrySet()) { - PaperweightGetBlocks.this.setHeightmapToGet(entry.getKey(), entry.getValue()); - } - PaperweightGetBlocks.this.setLightingToGet( - set.getLight(), - set.getMinSectionPosition(), - set.getMaxSectionPosition() - ); - PaperweightGetBlocks.this.setSkyLightingToGet( - set.getSkyLight(), - set.getMinSectionPosition(), - set.getMaxSectionPosition() - ); - - Runnable[] syncTasks = null; - - int bx = chunkX << 4; - int bz = chunkZ << 4; - - // Call beacon deactivate events here synchronously - // list will be null on spigot, so this is an implicit isPaper check - if (beacons != null && !beacons.isEmpty()) { - final List finalBeacons = beacons; - - syncTasks = new Runnable[4]; - - syncTasks[3] = () -> { - for (BlockEntity beacon : finalBeacons) { - BeaconBlockEntity.playSound(beacon.getLevel(), beacon.getBlockPos(), SoundEvents.BEACON_DEACTIVATE); - new BeaconDeactivatedEvent(CraftBlock.at(beacon.getLevel(), beacon.getBlockPos())).callEvent(); - } - }; - } - - Set entityRemoves = set.getEntityRemoves(); - if (entityRemoves != null && !entityRemoves.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[3]; - } - - syncTasks[2] = () -> { - Set entitiesRemoved = new HashSet<>(); - final List entities = PaperweightPlatformAdapter.getEntities(nmsChunk); - - for (Entity entity : entities) { - UUID uuid = entity.getUUID(); - if (entityRemoves.contains(uuid)) { - if (createCopy) { - copy.storeEntity(entity); - } - removeEntity(entity); - entitiesRemoved.add(uuid); - entityRemoves.remove(uuid); - } - } - if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { - for (UUID uuid : entityRemoves) { - Entity entity = nmsWorld.getEntities().get(uuid); - if (entity != null) { - removeEntity(entity); - } - } - } - // Only save entities that were actually removed to history - set.getEntityRemoves().clear(); - set.getEntityRemoves().addAll(entitiesRemoved); - }; - } - - Set entities = set.getEntities(); - if (entities != null && !entities.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[2]; - } - - syncTasks[1] = () -> { - Iterator iterator = entities.iterator(); - while (iterator.hasNext()) { - final CompoundTag nativeTag = iterator.next(); - final Map> entityTagMap = nativeTag.getValue(); - final StringTag idTag = (StringTag) entityTagMap.get("Id"); - final ListTag posTag = (ListTag) entityTagMap.get("Pos"); - final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); - if (idTag == null || posTag == null || rotTag == null) { - LOGGER.error("Unknown entity tag: {}", nativeTag); - continue; - } - final double x = posTag.getDouble(0); - final double y = posTag.getDouble(1); - final double z = posTag.getDouble(2); - final float yaw = rotTag.getFloat(0); - final float pitch = rotTag.getFloat(1); - final String id = idTag.getValue(); - - EntityType type = EntityType.byString(id).orElse(null); - if (type != null) { - Entity entity = type.create(nmsWorld); - if (entity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); - for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - entity.load(tag); - entity.absMoveTo(x, y, z, yaw, pitch); - entity.setUUID(nativeTag.getUUID()); - if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { - LOGGER.warn( - "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", - id, - nmsWorld.getWorld().getName(), - x, - y, - z - ); - // Unsuccessful create should not be saved to history - iterator.remove(); - } - } - } - } - }; - } - - // set tiles - Map tiles = set.getTiles(); - if (tiles != null && !tiles.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[1]; - } - - syncTasks[0] = () -> { - for (final Map.Entry entry : tiles.entrySet()) { - final CompoundTag nativeTag = entry.getValue(); - final BlockVector3 blockHash = entry.getKey(); - final int x = blockHash.x() + bx; - final int y = blockHash.y(); - final int z = blockHash.z() + bz; - final BlockPos pos = new BlockPos(x, y, z); - - synchronized (nmsWorld) { - BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); - if (tileEntity == null || tileEntity.isRemoved()) { - nmsWorld.removeBlockEntity(pos); - tileEntity = nmsWorld.getBlockEntity(pos); - } - if (tileEntity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); - tag.put("x", IntTag.valueOf(x)); - tag.put("y", IntTag.valueOf(y)); - tag.put("z", IntTag.valueOf(z)); - tileEntity.load(tag); - } - } - } - }; - } - - Runnable callback; - if (bitMask == 0 && biomes == null && !lightUpdate) { - callback = null; - } else { - int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; - boolean finalLightUpdate = lightUpdate; - callback = () -> { - // Set Modified - nmsChunk.setLightCorrect(true); // Set Modified - nmsChunk.mustNotSave = false; - nmsChunk.setUnsaved(true); - // send to player - if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING || finalMask == 0 && biomes != null) { - this.send(); - } - if (finalizer != null) { - finalizer.run(); - } - }; - } - if (syncTasks != null) { - QueueHandler queueHandler = Fawe.instance().getQueueHandler(); - Runnable[] finalSyncTasks = syncTasks; - - // Chain the sync tasks and the callback - Callable chain = () -> { - try { - // Run the sync tasks - for (Runnable task : finalSyncTasks) { - if (task != null) { - task.run(); - } - } - if (callback == null) { - if (finalizer != null) { - queueHandler.async(finalizer, null); - } - return null; - } else { - return queueHandler.async(callback, null); - } - } catch (Throwable e) { - e.printStackTrace(); - throw e; - } - }; - //noinspection unchecked - required at compile time - return (T) (Future) queueHandler.sync(chain); - } else { - if (callback == null) { - if (finalizer != null) { - finalizer.run(); - } - } else { - callback.run(); - } - } - } - return null; - } catch (Throwable e) { - e.printStackTrace(); - return null; - } finally { - forceLoadSections = true; - } - } - - private void updateGet( - LevelChunk nmsChunk, - LevelChunkSection[] chunkSections, - LevelChunkSection section, - char[] arr, - int layer - ) { - try { - sectionLock.writeLock().lock(); - if (this.getChunk() != nmsChunk) { - this.levelChunk = nmsChunk; - this.sections = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); - this.reset(); - } - if (this.sections == null) { - this.sections = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); - } - if (this.sections[layer] != section) { - // Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords - this.sections[layer] = new LevelChunkSection[]{section}.clone()[0]; - } - } finally { - sectionLock.writeLock().unlock(); - } - this.blocks[layer] = arr; - } - - private char[] loadPrivately(int layer) { - layer -= getMinSectionPosition(); - if (super.sections[layer] != null) { - synchronized (super.sectionLocks[layer]) { - if (super.sections[layer].isFull() && super.blocks[layer] != null) { - return super.blocks[layer]; - } - } - } - return PaperweightGetBlocks.this.update(layer, null, true); - } - - @Override - public void send() { - synchronized (sendLock) { - PaperweightPlatformAdapter.sendChunk(this, serverLevel, chunkX, chunkZ); - } - } - - /** - * Update a given (nullable) data array to the current data stored in the server's chunk, associated with this - * {@link PaperweightPlatformAdapter} instance. Not synchronised to the {@link PaperweightPlatformAdapter} instance as synchronisation - * is handled where necessary in the method, and should otherwise be handled correctly by this method's caller. - * - * @param layer layer index (0 may denote a negative layer in the world, e.g. at y=-32) - * @param data array to be updated/filled with data or null - * @param aggressive if the cached section array should be re-acquired. - * @return the given array to be filled with data, or a new array if null is given. - */ - @Override - @SuppressWarnings("unchecked") - public char[] update(int layer, char[] data, boolean aggressive) { - LevelChunkSection section = getSections(aggressive)[layer]; - // Section is null, return empty array - if (section == null) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - return data; - } - if (data != null && data.length != 4096) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - } - if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - } - Semaphore lock = PaperweightPlatformAdapter.applyLock(section); - synchronized (lock) { - // Efficiently convert ChunkSection to raw data - try { - lock.acquire(); - - final PalettedContainer blocks = section.getStates(); - final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocks); - final BitStorage bits = (BitStorage) PaperweightPlatformAdapter.fieldStorage.get(dataObject); - - if (bits instanceof ZeroBitStorage) { - Arrays.fill(data, adapter.adaptToChar(blocks.get(0, 0, 0))); // get(int) is only public on paper - return data; - } - - final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get(dataObject); - - final int bitsPerEntry = bits.getBits(); - final long[] blockStates = bits.getRaw(); - - new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).toRaw(data); - - int num_palette; - if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { - num_palette = palette.getSize(); - } else { - // The section's palette is the global block palette. - for (int i = 0; i < 4096; i++) { - char paletteVal = data[i]; - char ordinal = adapter.ibdIDToOrdinal(paletteVal); - data[i] = ordinal; - } - return data; - } - - char[] paletteToOrdinal = FaweCache.INSTANCE.PALETTE_TO_BLOCK_CHAR.get(); - try { - if (num_palette != 1) { - for (int i = 0; i < num_palette; i++) { - char ordinal = ordinal(palette.valueFor(i), adapter); - paletteToOrdinal[i] = ordinal; - } - for (int i = 0; i < 4096; i++) { - char paletteVal = data[i]; - char val = paletteToOrdinal[paletteVal]; - if (val == Character.MAX_VALUE) { - val = ordinal(palette.valueFor(i), adapter); - paletteToOrdinal[i] = val; - } - data[i] = val; - } - } else { - char ordinal = ordinal(palette.valueFor(0), adapter); - Arrays.fill(data, ordinal); - } - } finally { - for (int i = 0; i < num_palette; i++) { - paletteToOrdinal[i] = Character.MAX_VALUE; - } - } - return data; - } catch (IllegalAccessException | InterruptedException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } finally { - lock.release(); - } - } - } - - private char ordinal(BlockState ibd, PaperweightFaweAdapter adapter) { - if (ibd == null) { - return BlockTypesCache.ReservedIDs.AIR; - } else { - return adapter.adaptToChar(ibd); - } - } - - public LevelChunkSection[] getSections(boolean force) { - force &= forceLoadSections; - LevelChunkSection[] tmp = sections; - if (tmp == null || force) { - try { - sectionLock.writeLock().lock(); - tmp = sections; - if (tmp == null || force) { - LevelChunkSection[] chunkSections = getChunk().getSections(); - tmp = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length); - sections = tmp; - } - } finally { - sectionLock.writeLock().unlock(); - } - } - return tmp; - } - - public LevelChunk getChunk() { - LevelChunk levelChunk = this.levelChunk; - if (levelChunk == null) { - synchronized (this) { - levelChunk = this.levelChunk; - if (levelChunk == null) { - this.levelChunk = levelChunk = ensureLoaded(this.serverLevel, chunkX, chunkZ); - } - } - } - return levelChunk; - } - - private void fillLightNibble(char[][] light, LightLayer lightLayer, int minSectionPosition, int maxSectionPosition) { - for (int Y = 0; Y <= maxSectionPosition - minSectionPosition; Y++) { - if (light[Y] == null) { - continue; - } - SectionPos sectionPos = SectionPos.of(levelChunk.getPos(), Y + minSectionPosition); - DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(lightLayer).getDataLayerData( - sectionPos); - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - Arrays.fill(LAYER_COUNT, lightLayer == LightLayer.SKY ? (byte) 15 : (byte) 0); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( - lightLayer, - sectionPos, - dataLayer - ); - } - synchronized (dataLayer) { - for (int x = 0; x < 16; x++) { - for (int y = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { - int i = y << 8 | z << 4 | x; - if (light[Y][i] < 16) { - dataLayer.set(x, y, z, light[Y][i]); - } - } - } - } - } - } - } - - private PalettedContainer> setBiomesToPalettedContainer( - final BiomeType[][] biomes, - final int sectionIndex, - final PalettedContainerRO> data - ) { - BiomeType[] sectionBiomes; - if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { - return null; - } - PalettedContainer> biomeData = data.recreate(); - for (int y = 0, index = 0; y < 4; y++) { - for (int z = 0; z < 4; z++) { - for (int x = 0; x < 4; x++, index++) { - BiomeType biomeType = sectionBiomes[index]; - if (biomeType == null) { - biomeData.set(x, y, z, data.get(x, y, z)); - } else { - biomeData.set( - x, - y, - z, - biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) - ); - } - } - } - } - return biomeData; - } - - @Override - public boolean hasSection(int layer) { - layer -= getMinSectionPosition(); - return getSections(false)[layer] != null; - } - - @Override - @SuppressWarnings("unchecked") - public synchronized boolean trim(boolean aggressive) { - skyLight = new DataLayer[getSectionCount()]; - blockLight = new DataLayer[getSectionCount()]; - if (aggressive) { - sectionLock.writeLock().lock(); - sections = null; - levelChunk = null; - sectionLock.writeLock().unlock(); - return super.trim(true); - } else if (sections == null) { - // don't bother trimming if there are no sections stored. - return true; - } else { - for (int i = getMinSectionPosition(); i <= getMaxSectionPosition(); i++) { - int layer = i - getMinSectionPosition(); - if (!hasSection(i) || !super.sections[layer].isFull()) { - continue; - } - LevelChunkSection existing = getSections(true)[layer]; - try { - final PalettedContainer blocksExisting = existing.getStates(); - - final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocksExisting); - final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get( - dataObject); - int paletteSize; - - if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { - paletteSize = palette.getSize(); - } else { - super.trim(false, i); - continue; - } - if (paletteSize == 1) { - //If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks. - continue; - } - super.trim(false, i); - } catch (IllegalAccessException ignored) { - super.trim(false, i); - } - } - return true; - } - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java deleted file mode 100644 index d2412b98f..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java +++ /dev/null @@ -1,259 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; - -import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; -import com.fastasyncworldedit.core.queue.IBlocks; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.math.BlockVector3; -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.BlockTypesCache; -import net.minecraft.core.Holder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import org.apache.logging.log4j.Logger; - -import javax.annotation.Nullable; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Future; - -public class PaperweightGetBlocks_Copy implements IChunkGet { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private final Map tiles = new HashMap<>(); - private final Set entities = new HashSet<>(); - private final char[][] blocks; - private final int minHeight; - private final int maxHeight; - final ServerLevel serverLevel; - final LevelChunk levelChunk; - private Holder[][] biomes = null; - - protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { - this.levelChunk = levelChunk; - this.serverLevel = levelChunk.level; - this.minHeight = serverLevel.getMinBuildHeight(); - this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. - this.blocks = new char[getSectionCount()][]; - } - - protected void storeTile(BlockEntity blockEntity) { - tiles.put( - BlockVector3.at( - blockEntity.getBlockPos().getX(), - blockEntity.getBlockPos().getY(), - blockEntity.getBlockPos().getZ() - ), - new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)) - ); - } - - @Override - public Map getTiles() { - return tiles; - } - - @Override - @Nullable - public CompoundTag getTile(int x, int y, int z) { - return tiles.get(BlockVector3.at(x, y, z)); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - protected void storeEntity(Entity entity) { - BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(entity, compoundTag); - entities.add((CompoundTag) adapter.toNative(compoundTag)); - } - - @Override - public Set getEntities() { - return this.entities; - } - - @Override - public CompoundTag getEntity(UUID uuid) { - for (CompoundTag tag : entities) { - if (uuid.equals(tag.getUUID())) { - return tag; - } - } - return null; - } - - @Override - public boolean isCreateCopy() { - return false; - } - - @Override - public int setCreateCopy(boolean createCopy) { - return -1; - } - - @Override - public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { - } - - @Override - public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { - } - - @Override - public void setHeightmapToGet(HeightMapType type, int[] data) { - } - - @Override - public int getMaxY() { - return maxHeight; - } - - @Override - public int getMinY() { - return minHeight; - } - - @Override - public int getMaxSectionPosition() { - return maxHeight >> 4; - } - - @Override - public int getMinSectionPosition() { - return minHeight >> 4; - } - - @Override - public BiomeType getBiomeType(int x, int y, int z) { - Holder biome = biomes[(y >> 4) - getMinSectionPosition()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2]; - return PaperweightPlatformAdapter.adapt(biome, serverLevel); - } - - @Override - public void removeSectionLighting(int layer, boolean sky) { - } - - @Override - public boolean trim(boolean aggressive, int layer) { - return false; - } - - @Override - public IBlocks reset() { - return null; - } - - @Override - public int getSectionCount() { - return serverLevel.getSectionsCount(); - } - - protected void storeSection(int layer, char[] data) { - blocks[layer] = data; - } - - protected void storeBiomes(int layer, PalettedContainerRO> biomeData) { - if (biomes == null) { - biomes = new Holder[getSectionCount()][]; - } - if (biomes[layer] == null) { - biomes[layer] = new Holder[64]; - } - if (biomeData instanceof PalettedContainer> palettedContainer) { - for (int i = 0; i < 64; i++) { - biomes[layer][i] = palettedContainer.get(i); - } - } else { - LOGGER.error( - "Cannot correctly save biomes to history. Expected class type {} but got {}", - PalettedContainer.class.getSimpleName(), - biomeData.getClass().getSimpleName() - ); - } - } - - @Override - public BaseBlock getFullBlock(int x, int y, int z) { - BlockState state = BlockTypesCache.states[get(x, y, z)]; - return state.toBaseBlock(this, x, y, z); - } - - @Override - public boolean hasSection(int layer) { - layer -= getMinSectionPosition(); - return blocks[layer] != null; - } - - @Override - public char[] load(int layer) { - layer -= getMinSectionPosition(); - if (blocks[layer] == null) { - blocks[layer] = new char[4096]; - Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR); - } - return blocks[layer]; - } - - @Override - public char[] loadIfPresent(int layer) { - layer -= getMinSectionPosition(); - return blocks[layer]; - } - - @Override - public BlockState getBlock(int x, int y, int z) { - return BlockTypesCache.states[get(x, y, z)]; - } - - @Override - public int getSkyLight(int x, int y, int z) { - return 0; - } - - @Override - public int getEmittedLight(int x, int y, int z) { - return 0; - } - - @Override - public int[] getHeightMap(HeightMapType type) { - return new int[0]; - } - - @Override - public > T call(IChunkSet set, Runnable finalize) { - return null; - } - - public char get(int x, int y, int z) { - final int layer = (y >> 4) - getMinSectionPosition(); - final int index = (y & 15) << 8 | z << 4 | x; - return blocks[layer][index]; - } - - - @Override - public boolean trim(boolean aggressive) { - return false; - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightMapChunkUtil.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightMapChunkUtil.java deleted file mode 100644 index 62f5d4e03..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightMapChunkUtil.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; - -import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; - -//TODO un-very-break-this -public class PaperweightMapChunkUtil extends MapChunkUtil { - - public PaperweightMapChunkUtil() throws NoSuchFieldException { - fieldX = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("TWO_MEGABYTES", "a")); - fieldZ = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("x", "a")); - fieldBitMask = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("z", "b")); - fieldHeightMap = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("heightmaps", "b")); - fieldChunkData = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("chunkData", "c")); - fieldBlockEntities = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("buffer", "c")); - fieldFull = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("blockEntitiesData", "d")); - fieldX.setAccessible(true); - fieldZ.setAccessible(true); - fieldBitMask.setAccessible(true); - fieldHeightMap.setAccessible(true); - fieldChunkData.setAccessible(true); - fieldBlockEntities.setAccessible(true); - fieldFull.setAccessible(true); - } - - @Override - public ClientboundLevelChunkWithLightPacket createPacket() { - // TODO ??? return new ClientboundLevelChunkPacket(); - throw new UnsupportedOperationException(); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java deleted file mode 100644 index 05c0b58f9..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java +++ /dev/null @@ -1,764 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; - -import com.destroystokyo.paper.util.maplist.EntityList; -import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; -import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; -import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.math.BitArrayUnstretched; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.ReflectionUtils; -import com.fastasyncworldedit.core.util.TaskManager; -import com.mojang.datafixers.util.Either; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -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.BlockTypesCache; -import io.papermc.lib.PaperLib; -import io.papermc.paper.world.ChunkEntitySlices; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.IdMap; -import net.minecraft.core.Registry; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.level.TicketType; -import net.minecraft.util.BitStorage; -import net.minecraft.util.ExceptionCollector; -import net.minecraft.util.SimpleBitStorage; -import net.minecraft.util.ThreadingDetector; -import net.minecraft.util.Unit; -import net.minecraft.util.ZeroBitStorage; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.npc.AbstractVillager; -import net.minecraft.world.entity.npc.Villager; -import net.minecraft.world.item.trading.MerchantOffers; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.GlobalPalette; -import net.minecraft.world.level.chunk.HashMapPalette; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.LinearPalette; -import net.minecraft.world.level.chunk.Palette; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.SingleValuePalette; -import net.minecraft.world.level.entity.PersistentEntitySectionManager; -import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_20_R1.CraftChunk; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.function.Function; - -import static java.lang.invoke.MethodType.methodType; -import static net.minecraft.core.registries.Registries.BIOME; - -public final class PaperweightPlatformAdapter extends NMSAdapter { - - public static final Field fieldData; - - public static final Constructor dataConstructor; - - public static final Field fieldStorage; - public static final Field fieldPalette; - - private static final Field fieldTickingFluidCount; - private static final Field fieldTickingBlockCount; - - private static final MethodHandle methodGetVisibleChunk; - - private static final Field fieldThreadingDetector; - private static final Field fieldLock; - - private static final MethodHandle methodRemoveGameEventListener; - private static final MethodHandle methodremoveTickingBlockEntity; - private static final Field fieldBiomes; - - private static final Field fieldOffers; - private static final MerchantOffers OFFERS = new MerchantOffers(); - - /* - * This is a workaround for the changes from https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/1fddefce1cdce44010927b888432bf70c0e88cde#src/main/java/org/bukkit/craftbukkit/CraftChunk.java - * and is only needed to support 1.19.4 versions before *and* after this change. - */ - private static final MethodHandle CRAFT_CHUNK_GET_HANDLE; - - private static final Field fieldRemove; - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - static final boolean POST_CHUNK_REWRITE; - private static Method PAPER_CHUNK_GEN_ALL_ENTITIES; - private static Field LEVEL_CHUNK_ENTITIES; - private static Field SERVER_LEVEL_ENTITY_MANAGER; - - static { - final MethodHandles.Lookup lookup = MethodHandles.lookup(); - try { - fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d")); - fieldData.setAccessible(true); - - Class dataClazz = fieldData.getType(); - dataConstructor = dataClazz.getDeclaredConstructors()[0]; - dataConstructor.setAccessible(true); - - fieldStorage = dataClazz.getDeclaredField(Refraction.pickName("storage", "b")); - fieldStorage.setAccessible(true); - fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c")); - fieldPalette.setAccessible(true); - - fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "g")); - fieldTickingFluidCount.setAccessible(true); - fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); - fieldTickingBlockCount.setAccessible(true); - Field tmpFieldBiomes; - try { - // It seems to actually be biomes, but is apparently obfuscated to "i" - tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); - } catch (NoSuchFieldException ignored) { - tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i"); - } - fieldBiomes = tmpFieldBiomes; - fieldBiomes.setAccessible(true); - - Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( - "getVisibleChunkIfPresent", - "b" - ), long.class); - getVisibleChunkIfPresent.setAccessible(true); - methodGetVisibleChunk = lookup.unreflect(getVisibleChunkIfPresent); - - if (!PaperLib.isPaper()) { - fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); - fieldThreadingDetector.setAccessible(true); - fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); - fieldLock.setAccessible(true); - } else { - // in paper, the used methods are synchronized properly - fieldThreadingDetector = null; - fieldLock = null; - } - - Method removeGameEventListener = LevelChunk.class.getDeclaredMethod( - Refraction.pickName("removeGameEventListener", "a"), - BlockEntity.class, - ServerLevel.class - ); - removeGameEventListener.setAccessible(true); - methodRemoveGameEventListener = lookup.unreflect(removeGameEventListener); - - Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod( - Refraction.pickName( - "removeBlockEntityTicker", - "l" - ), BlockPos.class - ); - removeBlockEntityTicker.setAccessible(true); - methodremoveTickingBlockEntity = lookup.unreflect(removeBlockEntityTicker); - - fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "q")); - fieldRemove.setAccessible(true); - - boolean chunkRewrite; - try { - ServerLevel.class.getDeclaredMethod("getEntityLookup"); - chunkRewrite = true; - PAPER_CHUNK_GEN_ALL_ENTITIES = ChunkEntitySlices.class.getDeclaredMethod("getAllEntities"); - PAPER_CHUNK_GEN_ALL_ENTITIES.setAccessible(true); - } catch (NoSuchMethodException ignored) { - chunkRewrite = false; - } - try { - // Paper - Pre-Chunk-Update - LEVEL_CHUNK_ENTITIES = LevelChunk.class.getDeclaredField("entities"); - LEVEL_CHUNK_ENTITIES.setAccessible(true); - } catch (NoSuchFieldException ignored) { - } - try { - // Non-Paper - SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "M")); - SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true); - } catch (NoSuchFieldException ignored) { - } - POST_CHUNK_REWRITE = chunkRewrite; - - fieldOffers = AbstractVillager.class.getDeclaredField(Refraction.pickName("offers", "bU")); - fieldOffers.setAccessible(true); - } catch (RuntimeException | Error e) { - throw e; - } catch (Exception e) { - throw new RuntimeException(e); - } - MethodHandle craftChunkGetHandle; - final MethodType type = methodType(LevelChunk.class); - try { - craftChunkGetHandle = lookup.findVirtual(CraftChunk.class, "getHandle", type); - } catch (NoSuchMethodException | IllegalAccessException e) { - try { - final MethodType newType = methodType(ChunkAccess.class, ChunkStatus.class); - craftChunkGetHandle = lookup.findVirtual(CraftChunk.class, "getHandle", newType); - craftChunkGetHandle = MethodHandles.insertArguments(craftChunkGetHandle, 1, ChunkStatus.FULL); - } catch (NoSuchMethodException | IllegalAccessException ex) { - throw new RuntimeException(ex); - } - } - CRAFT_CHUNK_GET_HANDLE = craftChunkGetHandle; - } - - static boolean setSectionAtomic( - LevelChunkSection[] sections, - LevelChunkSection expected, - LevelChunkSection value, - int layer - ) { - if (layer >= 0 && layer < sections.length) { - return ReflectionUtils.compareAndSet(sections, expected, value, layer); - } - return false; - } - - // There is no point in having a functional semaphore for paper servers. - private static final ThreadLocal SEMAPHORE_THREAD_LOCAL = - ThreadLocal.withInitial(() -> new DelegateSemaphore(1, null)); - - static DelegateSemaphore applyLock(LevelChunkSection section) { - if (PaperLib.isPaper()) { - return SEMAPHORE_THREAD_LOCAL.get(); - } - try { - synchronized (section) { - PalettedContainer blocks = section.getStates(); - ThreadingDetector currentThreadingDetector = (ThreadingDetector) fieldThreadingDetector.get(blocks); - synchronized (currentThreadingDetector) { - Semaphore currentLock = (Semaphore) fieldLock.get(currentThreadingDetector); - if (currentLock instanceof DelegateSemaphore delegateSemaphore) { - return delegateSemaphore; - } - DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); - fieldLock.set(currentThreadingDetector, newLock); - return newLock; - } - } - } catch (Throwable e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - } - - public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) { - if (!PaperLib.isPaper()) { - LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false); - if (nmsChunk != null) { - return nmsChunk; - } - if (Fawe.isMainThread()) { - return serverLevel.getChunk(chunkX, chunkZ); - } - } else { - LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ); - if (nmsChunk != null) { - addTicket(serverLevel, chunkX, chunkZ); - return nmsChunk; - } - nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ); - if (nmsChunk != null) { - addTicket(serverLevel, chunkX, chunkZ); - return nmsChunk; - } - // Avoid "async" methods from the main thread. - if (Fawe.isMainThread()) { - return serverLevel.getChunk(chunkX, chunkZ); - } - CompletableFuture future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true); - try { - CraftChunk chunk; - try { - chunk = (CraftChunk) future.get(10, TimeUnit.SECONDS); - } catch (TimeoutException e) { - String world = serverLevel.getWorld().getName(); - // We've already taken 10 seconds we can afford to wait a little here. - boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null); - if (loaded) { - LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world); - // Retry chunk load - chunk = (CraftChunk) serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true).get(); - } else { - throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!"); - } - } - addTicket(serverLevel, chunkX, chunkZ); - return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk); - } catch (Throwable e) { - e.printStackTrace(); - } - } - return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)); - } - - private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) { - // Ensure chunk is definitely loaded before applying a ticket - io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel - .getChunkSource() - .addRegionTicket(TicketType.UNLOAD_COOLDOWN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE)); - } - - public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) { - ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap; - try { - return (ChunkHolder) methodGetVisibleChunk.invoke(chunkMap, ChunkPos.asLong(chunkX, chunkZ)); - } catch (Throwable thr) { - throw new RuntimeException(thr); - } - } - - @SuppressWarnings("deprecation") - public static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int chunkZ) { - ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); - if (chunkHolder == null) { - return; - } - ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ); - LevelChunk levelChunk; - if (PaperLib.isPaper()) { - // getChunkAtIfLoadedImmediately is paper only - levelChunk = nmsWorld - .getChunkSource() - .getChunkAtIfLoadedImmediately(chunkX, chunkZ); - } else { - levelChunk = ((Optional) ((Either) chunkHolder - .getTickingChunkFuture() // method is not present with new paper chunk system - .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left()) - .orElse(null); - } - if (levelChunk == null) { - return; - } - MinecraftServer.getServer().execute(() -> { - ClientboundLevelChunkWithLightPacket packet; - if (PaperLib.isPaper()) { - synchronized (chunk) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - false // last false is to not bother with x-ray - ); - } - } else { - synchronized (chunk) { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); - } - } - nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); - }); - } - - private static List nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) { - return serverLevel.getChunkSource().chunkMap.getPlayers(coordIntPair, false); - } - - /* - NMS conversion - */ - public static LevelChunkSection newChunkSection( - final int layer, - final char[] blocks, - CachedBukkitAdapter adapter, - Registry biomeRegistry, - @Nullable PalettedContainer> biomes - ) { - return newChunkSection(layer, null, blocks, adapter, biomeRegistry, biomes); - } - - public static LevelChunkSection newChunkSection( - final int layer, - final Function get, - char[] set, - CachedBukkitAdapter adapter, - Registry biomeRegistry, - @Nullable PalettedContainer> biomes - ) { - if (set == null) { - return newChunkSection(biomeRegistry, biomes); - } - final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); - final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); - final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get(); - final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get(); - try { - int num_palette; - if (get == null) { - num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter, null); - } else { - num_palette = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, get, set, adapter, null); - } - - int bitsPerEntry = MathMan.log2nlz(num_palette - 1); - if (bitsPerEntry > 0 && bitsPerEntry < 5) { - bitsPerEntry = 4; - } else if (bitsPerEntry > 8) { - bitsPerEntry = MathMan.log2nlz(Block.BLOCK_STATE_REGISTRY.size() - 1); - } - - int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes - final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); - final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong); - - if (num_palette == 1) { - for (int i = 0; i < blockBitArrayEnd; i++) { - blockStates[i] = 0; - } - } else { - final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntryNonZero, 4096, blockStates); - bitArray.fromRaw(blocksCopy); - } - - final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd); - final BitStorage nmsBits; - if (bitsPerEntry == 0) { - nmsBits = new ZeroBitStorage(4096); - } else { - nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits); - } - List palette; - if (bitsPerEntry < 9) { - palette = new ArrayList<>(); - for (int i = 0; i < num_palette; i++) { - int ordinal = paletteToBlock[i]; - blockToPalette[ordinal] = Integer.MAX_VALUE; - final BlockState state = BlockTypesCache.states[ordinal]; - palette.add(((PaperweightBlockMaterial) state.getMaterial()).getState()); - } - } else { - palette = List.of(); - } - - // Create palette with data - @SuppressWarnings("deprecation") // constructor is deprecated on paper, but needed to keep compatibility with spigot - final PalettedContainer blockStatePalettedContainer = - new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, - PalettedContainer.Strategy.SECTION_STATES, - PalettedContainer.Strategy.SECTION_STATES.getConfiguration(Block.BLOCK_STATE_REGISTRY, bitsPerEntry), - nmsBits, - palette - ); - if (biomes == null) { - IdMap> biomeHolderIdMap = biomeRegistry.asHolderIdMap(); - biomes = new PalettedContainer<>( - biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId( - BiomeTypes.PLAINS)), - PalettedContainer.Strategy.SECTION_BIOMES - ); - } - - return new LevelChunkSection(blockStatePalettedContainer, biomes); - } catch (final Throwable e) { - throw e; - } finally { - Arrays.fill(blockToPalette, Integer.MAX_VALUE); - Arrays.fill(paletteToBlock, Integer.MAX_VALUE); - Arrays.fill(blockStates, 0); - Arrays.fill(blocksCopy, 0); - } - } - - @SuppressWarnings("deprecation") // Only deprecated in paper - private static LevelChunkSection newChunkSection( - Registry biomeRegistry, - @Nullable PalettedContainer> biomes - ) { - if (biomes == null) { - return new LevelChunkSection(biomeRegistry); - } - PalettedContainer dataPaletteBlocks = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, - Blocks.AIR.defaultBlockState(), - PalettedContainer.Strategy.SECTION_STATES - ); - return new LevelChunkSection(dataPaletteBlocks, biomes); - } - - public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer> biomes) { - try { - fieldBiomes.set(section, biomes); - } catch (IllegalAccessException e) { - LOGGER.error("Could not set biomes to chunk section", e); - } - } - - /** - * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. - */ - public static PalettedContainer> getBiomePalettedContainer( - BiomeType[] biomes, - IdMap> biomeRegistry - ) { - if (biomes == null) { - return null; - } - BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); - // Don't stream this as typically will see 1-4 biomes; stream overhead is large for the small length - Map> palette = new HashMap<>(); - for (BiomeType biomeType : new LinkedList<>(Arrays.asList(biomes))) { - Holder biome; - if (biomeType == null) { - biome = biomeRegistry.byId(adapter.getInternalBiomeId(BiomeTypes.PLAINS)); - } else { - biome = biomeRegistry.byId(adapter.getInternalBiomeId(biomeType)); - } - palette.put(biomeType, biome); - } - int biomeCount = palette.size(); - int bitsPerEntry = MathMan.log2nlz(biomeCount - 1); - Object configuration = PalettedContainer.Strategy.SECTION_STATES.getConfiguration( - new FakeIdMapBiome(biomeCount), - bitsPerEntry - ); - if (bitsPerEntry > 3) { - bitsPerEntry = MathMan.log2nlz(biomeRegistry.size() - 1); - } - PalettedContainer> biomePalettedContainer = new PalettedContainer<>( - biomeRegistry, - biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), - PalettedContainer.Strategy.SECTION_BIOMES - ); - - final Palette> biomePalette; - if (bitsPerEntry == 0) { - biomePalette = new SingleValuePalette<>( - biomePalettedContainer.registry, - biomePalettedContainer, - new ArrayList<>(palette.values()) // Must be modifiable - ); - } else if (bitsPerEntry == 4) { - biomePalette = LinearPalette.create( - 4, - biomePalettedContainer.registry, - biomePalettedContainer, - new ArrayList<>(palette.values()) // Must be modifiable - ); - } else if (bitsPerEntry < 9) { - biomePalette = HashMapPalette.create( - bitsPerEntry, - biomePalettedContainer.registry, - biomePalettedContainer, - new ArrayList<>(palette.values()) // Must be modifiable - ); - } else { - biomePalette = GlobalPalette.create( - bitsPerEntry, - biomePalettedContainer.registry, - biomePalettedContainer, - null // unused - ); - } - - int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes - final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); - final int arrayLength = MathMan.ceilZero(64f / blocksPerLong); - - - BitStorage bitStorage = bitsPerEntry == 0 ? new ZeroBitStorage(64) : new SimpleBitStorage( - bitsPerEntry, - 64, - new long[arrayLength] - ); - - try { - Object data = dataConstructor.newInstance(configuration, bitStorage, biomePalette); - fieldData.set(biomePalettedContainer, data); - int index = 0; - for (int y = 0; y < 4; y++) { - for (int z = 0; z < 4; z++) { - for (int x = 0; x < 4; x++, index++) { - BiomeType biomeType = biomes[index]; - if (biomeType == null) { - continue; - } - Holder biome = biomeRegistry.byId(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId(biomeType)); - if (biome == null) { - continue; - } - biomePalettedContainer.set(x, y, z, biome); - } - } - } - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException(e); - } - return biomePalettedContainer; - } - - public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException { - fieldTickingFluidCount.setShort(section, (short) 0); - fieldTickingBlockCount.setShort(section, (short) 0); - } - - public static BiomeType adapt(Holder biome, LevelAccessor levelAccessor) { - final Registry biomeRegistry = levelAccessor.registryAccess().registryOrThrow(BIOME); - if (biomeRegistry.getKey(biome.value()) == null) { - return biomeRegistry.asHolderIdMap().getId(biome) == -1 ? BiomeTypes.OCEAN - : null; - } - return BiomeTypes.get(biome.unwrapKey().orElseThrow().location().toString()); - } - - static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { - try { - if (levelChunk.loaded || levelChunk.level.isClientSide()) { - BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos()); - if (blockEntity != null) { - if (!levelChunk.level.isClientSide) { - methodRemoveGameEventListener.invoke(levelChunk, beacon, levelChunk.level); - } - fieldRemove.set(beacon, true); - } - } - methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos()); - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - } - - static List getEntities(LevelChunk chunk) { - ExceptionCollector collector = new ExceptionCollector<>(); - if (PaperLib.isPaper()) { - if (POST_CHUNK_REWRITE) { - try { - //noinspection unchecked - return (List) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level.getEntityLookup().getChunk(chunk.locX, chunk.locZ)); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=true]", e); - } - } - try { - EntityList entityList = (EntityList) LEVEL_CHUNK_ENTITIES.get(chunk); - return List.of(entityList.getRawData()); - } catch (IllegalAccessException e) { - collector.add(new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=false]", e)); - // fall through - } - } - try { - //noinspection unchecked - return ((PersistentEntitySectionManager) (SERVER_LEVEL_ENTITY_MANAGER.get(chunk.level))).getEntities(chunk.getPos()); - } catch (IllegalAccessException e) { - collector.add(new RuntimeException("Failed to lookup entities [PAPER=false]", e)); - } - collector.throwIfPresent(); - return List.of(); - } - - public static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { - boolean unset = false; - if (entity instanceof Villager villager && !Fawe.isMainThread()) { - try { - if (fieldOffers.get(entity) == null) { - villager.setOffers(OFFERS); - unset = true; - } - } catch (IllegalAccessException e) { - throw new RuntimeException("Failed to set offers field to villager to avoid async catcher.", e); - } - } - entity.save(compoundTag); - if (unset) { - ((Villager) entity).setOffers(null); - } - } - - record FakeIdMapBlock(int size) implements IdMap { - - @Override - public int getId(final net.minecraft.world.level.block.state.BlockState entry) { - return 0; - } - - @Nullable - @Override - public net.minecraft.world.level.block.state.BlockState byId(final int index) { - return null; - } - - @Nonnull - @Override - public Iterator iterator() { - return Collections.emptyIterator(); - } - - } - - record FakeIdMapBiome(int size) implements IdMap { - - @Override - public int getId(final Biome entry) { - return 0; - } - - @Nullable - @Override - public Biome byId(final int index) { - return null; - } - - @Nonnull - @Override - public Iterator iterator() { - return Collections.emptyIterator(); - } - - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPostProcessor.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPostProcessor.java deleted file mode 100644 index 0c4bcff85..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPostProcessor.java +++ /dev/null @@ -1,175 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; - -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.ProcessorScope; -import com.fastasyncworldedit.core.queue.IBatchProcessor; -import com.fastasyncworldedit.core.queue.IChunk; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.fastasyncworldedit.core.registry.state.PropertyKey; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.Fluids; - -import javax.annotation.Nullable; - -public class PaperweightPostProcessor implements IBatchProcessor { - - @Override - public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) { - return set; - } - - @SuppressWarnings("deprecation") - @Override - public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) { - boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS; - // The PostProcessor shouldn't be added, but just in case - if (!tickFluid) { - return; - } - PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet; - layer: - for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) { - char[] set = iChunkSet.loadIfPresent(layer); - if (set == null) { - // No edit means no need to process - continue; - } - char[] get = null; - for (int i = 0; i < 4096; i++) { - char ordinal = set[i]; - char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__; - boolean fromGet = false; // Used for liquids - if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { - if (get == null) { - get = getBlocks.load(layer); - } - // If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't - // actually being set - if (get == null) { - continue layer; - } - fromGet = true; - ordinal = replacedOrdinal = get[i]; - } - if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { - continue; - } else if (!fromGet) { // if fromGet, don't do the same again - if (get == null) { - get = getBlocks.load(layer); - } - replacedOrdinal = get[i]; - } - boolean ticking = BlockTypesCache.ticking[ordinal]; - boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal]; - boolean replacedWasLiquid = false; - BlockState replacedState = null; - if (!ticking) { - // If the block being replaced was not ticking, it cannot be a liquid - if (!replacedWasTicking) { - continue; - } - // If the block being replaced is not fluid, we do not need to worry - if (!(replacedWasLiquid = - (replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) { - continue; - } - } - BlockState state = BlockState.getFromOrdinal(ordinal); - boolean liquid = state.getMaterial().isLiquid(); - int x = i & 15; - int y = (i >> 8) & 15; - int z = (i >> 4) & 15; - BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z); - if (liquid || replacedWasLiquid) { - if (liquid) { - addFluid(getBlocks.serverLevel, state, position); - continue; - } - // If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this - // may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up - // being ticked anyway. We only need it to be "hit" once. - if (!wasAdjacentToWater(get, set, i, x, y, z)) { - continue; - } - addFluid(getBlocks.serverLevel, replacedState, position); - } - } - } - } - - @Nullable - @Override - public Extent construct(final Extent child) { - throw new UnsupportedOperationException("Processing only"); - } - - @Override - public ProcessorScope getScope() { - return ProcessorScope.READING_SET_BLOCKS; - } - - private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) { - if (set == null || get == null) { - return false; - } - char ordinal; - char reserved = BlockTypesCache.ReservedIDs.__RESERVED__; - if (x > 0 && set[i - 1] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) { - return true; - } - } - if (x < 15 && set[i + 1] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) { - return true; - } - } - if (z > 0 && set[i - 16] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) { - return true; - } - } - if (z < 15 && set[i + 16] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) { - return true; - } - } - if (y > 0 && set[i - 256] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) { - return true; - } - } - if (y < 15 && set[i + 256] != reserved) { - return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal); - } - return false; - } - - @SuppressWarnings("deprecation") - private boolean isFluid(char ordinal) { - return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid(); - } - - @SuppressWarnings("deprecation") - private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) { - Fluid type; - if (replacedState.getBlockType() == BlockTypes.LAVA) { - type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA; - } else { - type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER; - } - serverLevel.scheduleTick( - position, - type, - type.getTickDelay(serverLevel) - ); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java deleted file mode 100644 index 7de83af21..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; - -import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.queue.IQueueExtent; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.TicketType; -import net.minecraft.util.Unit; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.chunk.ChunkStatus; - -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; -import java.util.function.IntConsumer; - -public class PaperweightStarlightRelighter extends StarlightRelighter { - - private static final TicketType FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); - private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkStatus.getDistance(ChunkStatus.LIGHT); - - public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { - super(serverLevel, queue); - } - - @Override - protected ChunkPos createChunkPos(final long chunkKey) { - return new ChunkPos(chunkKey); - } - - @Override - protected long asLong(final int chunkX, final int chunkZ) { - return ChunkPos.asLong(chunkX, chunkZ); - } - - @Override - protected CompletableFuture chunkLoadFuture(final ChunkPos chunkPos) { - return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z) - .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( - FAWE_TICKET, - chunkPos, - LIGHT_LEVEL, - Unit.INSTANCE - )); - } - - protected void invokeRelight( - Set coords, - Consumer chunkCallback, - IntConsumer processCallback - ) { - try { - serverLevel.getChunkSource().getLightEngine().relight(coords, chunkCallback, processCallback); - } catch (Exception e) { - LOGGER.error("Error occurred on relighting", e); - } - } - - /* - * Allow the server to unload the chunks again. - * Also, if chunk packets are sent delayed, we need to do that here - */ - protected void postProcessChunks(Set coords) { - boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING; - for (ChunkPos pos : coords) { - int x = pos.x; - int z = pos.z; - if (delay) { // we still need to send the block changes of that chunk - PaperweightPlatformAdapter.sendChunk(pos, serverLevel, x, z); - } - serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE); - } - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighterFactory.java deleted file mode 100644 index 83509a2bb..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighterFactory.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; - -import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; -import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; -import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; -import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IQueueExtent; -import com.sk89q.worldedit.world.World; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; - -import javax.annotation.Nonnull; - -public class PaperweightStarlightRelighterFactory implements RelighterFactory { - - @Override - public @Nonnull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { - org.bukkit.World w = Bukkit.getWorld(world.getName()); - if (w == null) { - return NullRelighter.INSTANCE; - } - return new PaperweightStarlightRelighter(((CraftWorld) w).getHandle(), queue); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/nbt/PaperweightLazyCompoundTag.java deleted file mode 100644 index f2a694a2f..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/nbt/PaperweightLazyCompoundTag.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.LazyCompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import net.minecraft.nbt.NumericTag; -import org.enginehub.linbus.tree.LinCompoundTag; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Supplier; - -public class PaperweightLazyCompoundTag extends LazyCompoundTag { - - private final Supplier compoundTagSupplier; - private CompoundTag compoundTag; - - public PaperweightLazyCompoundTag(Supplier compoundTagSupplier) { - super(new HashMap<>()); - this.compoundTagSupplier = compoundTagSupplier; - } - - public PaperweightLazyCompoundTag(net.minecraft.nbt.CompoundTag compoundTag) { - this(() -> compoundTag); - } - - public net.minecraft.nbt.CompoundTag get() { - return compoundTagSupplier.get(); - } - - @Override - @SuppressWarnings("unchecked") - public Map> getValue() { - if (compoundTag == null) { - compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); - } - return compoundTag.getValue(); - } - - @Override - public LinCompoundTag toLinTag() { - getValue(); - return compoundTag.toLinTag(); - } - - public boolean containsKey(String key) { - return compoundTagSupplier.get().contains(key); - } - - public byte[] getByteArray(String key) { - return compoundTagSupplier.get().getByteArray(key); - } - - public byte getByte(String key) { - return compoundTagSupplier.get().getByte(key); - } - - public double getDouble(String key) { - return compoundTagSupplier.get().getDouble(key); - } - - public double asDouble(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsDouble(); - } - return 0; - } - - public float getFloat(String key) { - return compoundTagSupplier.get().getFloat(key); - } - - public int[] getIntArray(String key) { - return compoundTagSupplier.get().getIntArray(key); - } - - public int getInt(String key) { - return compoundTagSupplier.get().getInt(key); - } - - public int asInt(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsInt(); - } - return 0; - } - - @SuppressWarnings("unchecked") - public List> getList(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof net.minecraft.nbt.ListTag nbtList) { - ArrayList> list = new ArrayList<>(); - for (net.minecraft.nbt.Tag elem : nbtList) { - if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { - list.add(new PaperweightLazyCompoundTag(compoundTag)); - } else { - list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem)); - } - } - return list; - } - return Collections.emptyList(); - } - - @SuppressWarnings("unchecked") - public ListTag getListTag(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof net.minecraft.nbt.ListTag) { - return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag); - } - return new ListTag(StringTag.class, Collections.emptyList()); - } - - @SuppressWarnings("unchecked") - public > List getList(String key, Class listType) { - ListTag listTag = getListTag(key); - if (listTag.getType().equals(listType)) { - return (List) listTag.getValue(); - } else { - return Collections.emptyList(); - } - } - - public long[] getLongArray(String key) { - return compoundTagSupplier.get().getLongArray(key); - } - - public long getLong(String key) { - return compoundTagSupplier.get().getLong(key); - } - - public long asLong(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsLong(); - } - return 0; - } - - public short getShort(String key) { - return compoundTagSupplier.get().getShort(key); - } - - public String getString(String key) { - return compoundTagSupplier.get().getString(key); - } - - @Override - public String toString() { - return compoundTagSupplier.get().toString(); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java deleted file mode 100644 index 99e001837..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java +++ /dev/null @@ -1,591 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.regen; - -import com.fastasyncworldedit.bukkit.adapter.Regenerator; -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.queue.IChunkCache; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.util.ReflectionUtils; -import com.fastasyncworldedit.core.util.TaskManager; -import com.google.common.collect.ImmutableList; -import com.mojang.datafixers.util.Either; -import com.mojang.serialization.Lifecycle; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.PaperweightGetBlocks; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.world.RegenOptions; -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.server.level.progress.ChunkProgressListener; -import net.minecraft.util.thread.ProcessorHandle; -import net.minecraft.util.thread.ProcessorMailbox; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.LevelSettings; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.BiomeSource; -import net.minecraft.world.level.biome.FixedBiomeSource; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkGenerator; -import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.FlatLevelSource; -import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; -import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; -import net.minecraft.world.level.levelgen.WorldOptions; -import net.minecraft.world.level.levelgen.blending.BlendingData; -import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; -import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; -import net.minecraft.world.level.storage.LevelStorageSource; -import net.minecraft.world.level.storage.PrimaryLevelData; -import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.craftbukkit.v1_20_R1.CraftServer; -import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R1.generator.CustomChunkGenerator; -import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; - -import javax.annotation.Nullable; -import java.lang.reflect.Field; -import java.nio.file.Path; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.OptionalLong; -import java.util.Random; -import java.util.concurrent.CompletableFuture; -import java.util.function.BooleanSupplier; -import java.util.function.Supplier; - -import static net.minecraft.core.registries.Registries.BIOME; - -public class PaperweightRegen extends Regenerator { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private static final Field serverWorldsField; - private static final Field paperConfigField; - private static final Field flatBedrockField; - private static final Field generatorSettingFlatField; - private static final Field generatorSettingBaseSupplierField; - private static final Field delegateField; - private static final Field chunkSourceField; - private static final Field generatorStructureStateField; - private static final Field ringPositionsField; - private static final Field hasGeneratedPositionsField; - - //list of chunk stati in correct order without FULL - private static final Map chunkStati = new LinkedHashMap<>(); - - static { - chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing - chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps - chunkStati.put( - ChunkStatus.STRUCTURE_REFERENCES, - Concurrency.FULL - ); // structure refs: radius 8, but only writes to current chunk - chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // biomes: radius 0 - chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8 - chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE - chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results - /*chunkStati.put( - ChunkStatus.LIQUID_CARVERS, - Concurrency.NONE - ); // liquid carvers: radius 0, but RADIUS and FULL change results*/ - chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps - chunkStati.put( - ChunkStatus.LIGHT, - Concurrency.FULL - ); // light: radius 1, but no writes to other chunks, only current chunk - chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0 - // chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0 - - try { - serverWorldsField = CraftServer.class.getDeclaredField("worlds"); - serverWorldsField.setAccessible(true); - - Field tmpPaperConfigField; - Field tmpFlatBedrockField; - try { //only present on paper - tmpPaperConfigField = Level.class.getDeclaredField("paperConfig"); - tmpPaperConfigField.setAccessible(true); - - tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock"); - tmpFlatBedrockField.setAccessible(true); - } catch (Exception e) { - tmpPaperConfigField = null; - tmpFlatBedrockField = null; - } - paperConfigField = tmpPaperConfigField; - flatBedrockField = tmpFlatBedrockField; - - generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName( - "settings", "e")); - generatorSettingBaseSupplierField.setAccessible(true); - - generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "d")); - generatorSettingFlatField.setAccessible(true); - - delegateField = CustomChunkGenerator.class.getDeclaredField("delegate"); - delegateField.setAccessible(true); - - chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "I")); - chunkSourceField.setAccessible(true); - - generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "v")); - generatorStructureStateField.setAccessible(true); - - ringPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(Refraction.pickName("ringPositions", "g")); - ringPositionsField.setAccessible(true); - - hasGeneratedPositionsField = ChunkGeneratorStructureState.class.getDeclaredField( - Refraction.pickName("hasGeneratedPositions", "h") - ); - hasGeneratedPositionsField.setAccessible(true); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - //runtime - private ServerLevel originalServerWorld; - private ServerChunkCache originalChunkProvider; - private ServerLevel freshWorld; - private ServerChunkCache freshChunkProvider; - private LevelStorageSource.LevelStorageAccess session; - private StructureTemplateManager structureTemplateManager; - private ThreadedLevelLightEngine threadedLevelLightEngine; - private ChunkGenerator chunkGenerator; - - private Path tempDir; - - private boolean generateFlatBedrock = false; - - public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) { - super(originalBukkitWorld, region, target, options); - } - - @Override - protected boolean prepare() { - this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle(); - originalChunkProvider = originalServerWorld.getChunkSource(); - - //flat bedrock? (only on paper) - if (paperConfigField != null) { - try { - generateFlatBedrock = flatBedrockField.getBoolean(paperConfigField.get(originalServerWorld)); - } catch (Exception ignored) { - } - } - - seed = options.getSeed().orElse(originalServerWorld.getSeed()); - chunkStati.forEach((s, c) -> super.chunkStatuses.put(new ChunkStatusWrap(s), c)); - - return true; - } - - @Override - @SuppressWarnings("unchecked") - protected boolean initNewWorld() throws Exception { - //world folder - tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen"); - - //prepare for world init (see upstream implementation for reference) - org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment(); - org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator(); - LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir); - ResourceKey levelStemResourceKey = getWorldDimKey(environment); - session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey); - PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData; - - MinecraftServer server = originalServerWorld.getCraftServer().getServer(); - WorldOptions originalOpts = originalWorldData.worldGenOptions(); - WorldOptions newOpts = options.getSeed().isPresent() - ? originalOpts.withSeed(OptionalLong.of(seed)) - : originalOpts; - LevelSettings newWorldSettings = new LevelSettings( - "faweregentempworld", - originalWorldData.settings.gameType(), - originalWorldData.settings.hardcore(), - originalWorldData.settings.difficulty(), - originalWorldData.settings.allowCommands(), - originalWorldData.settings.gameRules(), - originalWorldData.settings.getDataConfiguration() - ); - - PrimaryLevelData.SpecialWorldProperty specialWorldProperty = - originalWorldData.isFlatWorld() - ? PrimaryLevelData.SpecialWorldProperty.FLAT - : originalWorldData.isDebugWorld() - ? PrimaryLevelData.SpecialWorldProperty.DEBUG - : PrimaryLevelData.SpecialWorldProperty.NONE; - PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable()); - - BiomeProvider biomeProvider = getBiomeProvider(); - - - //init world - freshWorld = Fawe.instance().getQueueHandler().sync((Supplier) () -> new ServerLevel( - server, - server.executor, - session, - newWorldData, - originalServerWorld.dimension(), - DedicatedServer.getServer().registryAccess().registry(Registries.LEVEL_STEM).orElseThrow() - .getOrThrow(levelStemResourceKey), - new RegenNoOpWorldLoadListener(), - originalServerWorld.isDebug(), - seed, - ImmutableList.of(), - false, - originalServerWorld.getRandomSequences(), - environment, - generator, - biomeProvider - ) { - - private final Holder singleBiome = options.hasBiomeType() ? DedicatedServer.getServer().registryAccess() - .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( - WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) - ) : null; - - @Override - public void tick(BooleanSupplier shouldKeepTicking) { //no ticking - } - - @Override - public Holder getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { - if (options.hasBiomeType()) { - return singleBiome; - } - return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome( - biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler() - ); - } - }).get(); - freshWorld.noSave = true; - removeWorldFromWorldsMap(); - newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name - if (paperConfigField != null) { - paperConfigField.set(freshWorld, originalServerWorld.paperConfig()); - } - - ChunkGenerator originalGenerator = originalChunkProvider.getGenerator(); - if (originalGenerator instanceof FlatLevelSource flatLevelSource) { - FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings(); - chunkGenerator = new FlatLevelSource(generatorSettingFlat); - } else if (originalGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) { - Holder generatorSettingBaseSupplier = (Holder) generatorSettingBaseSupplierField.get( - originalGenerator); - BiomeSource biomeSource; - if (options.hasBiomeType()) { - - biomeSource = new FixedBiomeSource( - DedicatedServer.getServer().registryAccess() - .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( - WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) - ) - ); - } else { - biomeSource = originalGenerator.getBiomeSource(); - } - chunkGenerator = new NoiseBasedChunkGenerator( - biomeSource, - generatorSettingBaseSupplier - ); - } else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) { - chunkGenerator = customChunkGenerator.getDelegate(); - } else { - LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName()); - return false; - } - if (generator != null) { - chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator); - generateConcurrent = generator.isParallelCapable(); - } -// chunkGenerator.conf = freshWorld.spigotConfig; - Does not exist anymore, may need to be re-addressed - - freshChunkProvider = new ServerChunkCache( - freshWorld, - session, - server.getFixerUpper(), - server.getStructureManager(), - server.executor, - chunkGenerator, - freshWorld.spigotConfig.viewDistance, - freshWorld.spigotConfig.simulationDistance, - server.forceSynchronousWrites(), - new RegenNoOpWorldLoadListener(), - (chunkCoordIntPair, state) -> { - }, - () -> server.overworld().getDataStorage() - ) { - // redirect to LevelChunks created in #createChunks - @Override - public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean create) { - ChunkAccess chunkAccess = getChunkAt(x, z); - if (chunkAccess == null && create) { - chunkAccess = createChunk(getProtoChunkAt(x, z)); - } - return chunkAccess; - } - }; - - if (seed == originalOpts.seed() && !options.hasBiomeType()) { - // Optimisation for needless ring position calculation when the seed and biome is the same. - ChunkGeneratorStructureState state = (ChunkGeneratorStructureState) generatorStructureStateField.get(originalChunkProvider.chunkMap); - boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(state); - if (hasGeneratedPositions) { - Map>> origPositions = - (Map>>) ringPositionsField.get(state); - Map>> copy = new Object2ObjectArrayMap<>( - origPositions); - ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get(freshChunkProvider.chunkMap); - ringPositionsField.set(newState, copy); - hasGeneratedPositionsField.setBoolean(newState, true); - } - } - - - chunkSourceField.set(freshWorld, freshChunkProvider); - //let's start then - structureTemplateManager = server.getStructureManager(); - threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider); - - return true; - } - - @Override - protected void cleanup() { - try { - session.close(); - } catch (Exception ignored) { - } - - //shutdown chunk provider - try { - Fawe.instance().getQueueHandler().sync(() -> { - try { - freshChunkProvider.close(false); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - } catch (Exception ignored) { - } - - //remove world from server - try { - Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap); - } catch (Exception ignored) { - } - - //delete directory - try { - SafeFiles.tryHardToDeleteDir(tempDir); - } catch (Exception ignored) { - } - } - - @Override - protected ProtoChunk createProtoChunk(int x, int z) { - return new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld, - this.freshWorld.registryAccess().registryOrThrow(BIOME), null - ); - } - - @Override - protected LevelChunk createChunk(ProtoChunk protoChunk) { - return new LevelChunk( - freshWorld, - protoChunk, - null // we don't want to add entities - ); - } - - @Override - protected ChunkStatusWrap getFullChunkStatus() { - return new ChunkStatusWrap(ChunkStatus.FULL); - } - - @Override - protected List getBlockPopulators() { - return originalServerWorld.getWorld().getPopulators(); - } - - @Override - protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) { - // BlockPopulator#populate has to be called synchronously for TileEntity access - TaskManager.taskManager().task(() -> { - final CraftWorld world = freshWorld.getWorld(); - final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ); - blockPopulator.populate(world, random, chunk); - }); - } - - @Override - protected IChunkCache initSourceQueueCache() { - return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) { - @Override - public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) { - return getChunkAt(x, z); - } - }; - } - - //util - @SuppressWarnings("unchecked") - private void removeWorldFromWorldsMap() { - Fawe.instance().getQueueHandler().sync(() -> { - try { - Map map = (Map) serverWorldsField.get(Bukkit.getServer()); - map.remove("faweregentempworld"); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - }); - } - - private ResourceKey getWorldDimKey(org.bukkit.World.Environment env) { - return switch (env) { - case NETHER -> LevelStem.NETHER; - case THE_END -> LevelStem.END; - default -> LevelStem.OVERWORLD; - }; - } - - private static class RegenNoOpWorldLoadListener implements ChunkProgressListener { - - private RegenNoOpWorldLoadListener() { - } - - @Override - public void updateSpawnPos(ChunkPos spawnPos) { - } - - @Override - public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) { - } - - @Override - public void start() { - - } - - @Override - public void stop() { - } - - // TODO Paper only(?) @Override - public void setChunkRadius(int radius) { - } - - } - - private class FastProtoChunk extends ProtoChunk { - - public FastProtoChunk( - final ChunkPos pos, - final UpgradeData upgradeData, - final LevelHeightAccessor world, - final Registry biomeRegistry, - @Nullable final BlendingData blendingData - ) { - super(pos, upgradeData, world, biomeRegistry, blendingData); - } - - // avoid warning on paper - - // compatibility with spigot - - public boolean generateFlatBedrock() { - return generateFlatBedrock; - } - - // no one will ever see the entities! - @Override - public List getEntities() { - return Collections.emptyList(); - } - - } - - protected class ChunkStatusWrap extends ChunkStatusWrapper { - - private final ChunkStatus chunkStatus; - - public ChunkStatusWrap(ChunkStatus chunkStatus) { - this.chunkStatus = chunkStatus; - } - - @Override - public int requiredNeighborChunkRadius() { - return chunkStatus.getRange(); - } - - @Override - public String name() { - return chunkStatus.toString(); - } - - @Override - public CompletableFuture processChunk(List accessibleChunks) { - return chunkStatus.generate( - Runnable::run, // TODO revisit, we might profit from this somehow? - freshWorld, - chunkGenerator, - structureTemplateManager, - threadedLevelLightEngine, - c -> CompletableFuture.completedFuture(Either.left(c)), - accessibleChunks - ); - } - - } - - /** - * A light engine that does nothing. As light is calculated after pasting anyway, we can avoid - * work this way. - */ - static class NoOpLightEngine extends ThreadedLevelLightEngine { - - private static final ProcessorMailbox MAILBOX = ProcessorMailbox.create(task -> { - }, "fawe-no-op"); - private static final ProcessorHandle> HANDLE = ProcessorHandle.of("fawe-no-op", m -> { - }); - - public NoOpLightEngine(final ServerChunkCache chunkProvider) { - super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE); - } - - @Override - public CompletableFuture lightChunk(final ChunkAccess chunk, final boolean excludeBlocks) { - return CompletableFuture.completedFuture(chunk); - } - - } - -} From d2033d49ca00e52c90dce9b13e8e27a01303ce2f Mon Sep 17 00:00:00 2001 From: Zeranny Date: Sun, 21 Jul 2024 08:48:57 +0100 Subject: [PATCH 328/466] Fix parseFromInput Method for Masks and Patterns When Called via API (#2839) Explicitly Mask or Pattern in parseFromInput --- .../sk89q/worldedit/extension/factory/MaskFactory.java | 6 ++++++ .../worldedit/extension/factory/PatternFactory.java | 9 +++++++++ 2 files changed, 15 insertions(+) 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 3440b009c..dce3e1c4f 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 @@ -53,6 +53,7 @@ import com.sk89q.worldedit.extension.factory.parser.mask.NoiseMaskParser; import com.sk89q.worldedit.extension.factory.parser.mask.OffsetMaskParser; import com.sk89q.worldedit.extension.factory.parser.mask.RegionMaskParser; import com.sk89q.worldedit.extension.factory.parser.mask.SolidMaskParser; +import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.NoMatchException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.mask.Mask; @@ -132,6 +133,11 @@ public final class MaskFactory extends AbstractFactory { //FAWE start - rich mask parsing + @Override + public Mask parseFromInput(String input, ParserContext context) throws InputParseException { + return super.parseFromInput(input, context); + } + @Override protected Mask getParsed(final String input, final List masks) { return switch (masks.size()) { 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 25955adee..242d1d7bc 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 @@ -60,7 +60,9 @@ import com.sk89q.worldedit.extension.factory.parser.pattern.RandomPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.RandomStatePatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.SingleBlockPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.TypeOrStateApplyingPatternParser; +import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.RandomPattern; import com.sk89q.worldedit.internal.registry.AbstractFactory; @@ -130,6 +132,13 @@ public final class PatternFactory extends AbstractFactory { register(new VoronoiPatternParser(worldEdit)); } + //FAWE start - rich pattern parsing + + @Override + public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { + return super.parseFromInput(input, context); + } + @Override protected Pattern getParsed(final String input, final List patterns) { switch (patterns.size()) { From 01273e0ed7d77b61315e0e438452b07d9b27c162 Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 21 Jul 2024 14:59:12 +0200 Subject: [PATCH 329/466] fix: use new index calculations for BlockVectorSet remove (#2842) - fixes #2841 --- .../com/fastasyncworldedit/core/math/BlockVectorSet.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java index b181f9506..8911099af 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java @@ -192,12 +192,13 @@ public class BlockVectorSet extends AbstractCollection implements } public boolean remove(int x, int y, int z) { - int pair = MathMan.pair((short) (x >> 11), (short) (z >> 11)); - LocalBlockVectorSet localMap = localSets.get(pair); + int indexedY = (y + 128) >> 9; + long triple = MathMan.tripleWorldCoord((x >> 11), indexedY, (z >> 11)); + LocalBlockVectorSet localMap = localSets.get(triple); if (localMap != null) { - if (localMap.remove(x & 2047, y, z & 2047)) { + if (localMap.remove(x & 2047, ((y + 128) & 511) - 128, z & 2047)) { if (localMap.isEmpty()) { - localSets.remove(pair); + localSets.remove(triple); } return true; } From f65801c5a41e54a7875f5e41e37ce4ea1d1f265f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 Jul 2024 00:42:51 +0000 Subject: [PATCH 330/466] Update dependency org.checkerframework:checker-qual to v3.45.0 (#2847) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 79d9258b8..2c6294307 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.17.0" adventure-bukkit = "4.3.3" -checkerqual = "3.44.0" +checkerqual = "3.45.0" truezip = "6.8.4" auto-value = "1.11.0" findbugs = "3.0.2" From b5ff3282185f22ba50b5cceef15f1a0dec05bcc5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 Jul 2024 00:43:03 +0000 Subject: [PATCH 331/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.3.9 (#2846) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2c6294307..4f8f18a17 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.3.7" +towny = "0.100.3.9" plotsquared = "7.3.8" # Third party From ddacb976e4bc0e1140a3ce6061f5fd95c5f8e3f5 Mon Sep 17 00:00:00 2001 From: Jordan Date: Tue, 23 Jul 2024 19:53:12 +0200 Subject: [PATCH 332/466] fix: improve SchemGen, allow null mask (reordered command args) (#2817) - fixes #2815 --- .../command/tool/brush/PopulateSchem.java | 3 +- .../core/function/generator/SchemGen.java | 53 +++++++++++++++---- .../java/com/sk89q/worldedit/EditSession.java | 2 +- .../worldedit/command/BrushCommands.java | 4 +- .../com/sk89q/worldedit/extent/Extent.java | 25 ++++++--- 5 files changed, 67 insertions(+), 20 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/PopulateSchem.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/PopulateSchem.java index b28d7536b..59fc2add2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/PopulateSchem.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/PopulateSchem.java @@ -24,7 +24,8 @@ public record PopulateSchem(Mask mask, List clipboards, int rar CuboidRegion cuboid = new CuboidRegion( editSession.getWorld(), position.subtract(size1, size1, size1), - position.add(size1, size1, size1) + position.add(size1, size1, size1), + true ); try { editSession.addSchems(cuboid, mask, clipboards, rarity, randomRotate); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/SchemGen.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/SchemGen.java index 250914c05..83207f50b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/SchemGen.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/SchemGen.java @@ -7,6 +7,7 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.ClipboardHolder; import java.util.List; @@ -19,29 +20,60 @@ public class SchemGen implements Resource { private final List clipboards; private final boolean randomRotate; private final Mask mask; + private final Region region; private final MutableBlockVector3 mutable = new MutableBlockVector3(); + /** + * @deprecated Use {@link SchemGen#SchemGen(Mask, Extent, List, boolean, Region)} + */ + @Deprecated(forRemoval = true, since = "TODO") public SchemGen(Mask mask, Extent extent, List clipboards, boolean randomRotate) { this.mask = mask; this.extent = extent; this.clipboards = clipboards; this.randomRotate = randomRotate; + this.region = null; + } + + /** + * New instance. Places a schematic on terrain at a given x,z when appropriate + * + * @since TODO + */ + public SchemGen(Mask mask, Extent extent, List clipboards, boolean randomRotate, Region region) { + this.mask = mask; + this.extent = extent; + this.clipboards = clipboards; + this.randomRotate = randomRotate; + this.region = region; + } + + private int getY(int x, int z) { + if (region == null) { + return extent.getNearestSurfaceTerrainBlock( + x, + z, + mutable.y(), + this.extent.getMinY(), + this.extent.getMaxY(), + Integer.MIN_VALUE, + Integer.MAX_VALUE + ); + } else { + int y = extent.getHighestTerrainBlock(x, z, region.getMinimumY(), region.getMaximumY(), mask); + if (y == region.getMinimumY() && !extent.getBlock(x, y, z).getMaterial().isMovementBlocker()) { + return Integer.MIN_VALUE; + } + return y; + } } @Override public boolean spawn(Random random, int x, int z) throws WorldEditException { mutable.mutX(x); mutable.mutZ(z); - int y = extent.getNearestSurfaceTerrainBlock( - x, - z, - mutable.y(), - this.extent.getMinY(), - this.extent.getMaxY(), - Integer.MIN_VALUE, - Integer.MAX_VALUE - ); + int y = getY(x, z); if (y == Integer.MIN_VALUE || y == Integer.MAX_VALUE) { return false; } @@ -54,7 +86,8 @@ public class SchemGen implements Resource { if (randomRotate) { holder.setTransform(new AffineTransform().rotateY(ThreadLocalRandom.current().nextInt(4) * 90)); } - Clipboard clipboard = holder.getClipboard(); + Clipboard clipboard = holder.getClipboards().size() == 1 ? holder.getClipboard() : + holder.getClipboards().get(ThreadLocalRandom.current().nextInt(clipboards.size())); Transform transform = holder.getTransform(); if (transform.isIdentity()) { clipboard.paste(extent, mutable, false); 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 1469ffb96..926265bfb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -3881,7 +3881,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { @Override public void addSchems(Region region, Mask mask, List clipboards, int rarity, boolean rotate) throws WorldEditException { - spawnResource(region, new SchemGen(mask, this, clipboards, rotate), rarity, 1); + spawnResource(region, new SchemGen(mask, this, clipboards, rotate, region), rarity, 1); } @Override 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 7160be750..664e656c4 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 @@ -645,10 +645,10 @@ public class BrushCommands { @CommandPermissions("worldedit.brush.populateschematic") public void scatterSchemBrush( Player player, InjectedValueAccess context, - @Arg(desc = "Mask") - Mask mask, @Arg(name = "clipboard", desc = "Clipboard uri") String clipboardStr, + @Arg(desc = "Mask of block to place on. Defaults to solid blocks.", def = "") + Mask mask, @Arg(desc = "Expression", def = "30") Expression radius, @Arg(desc = "double", def = "50") 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 6117c6850..1b4420d27 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 @@ -216,7 +216,7 @@ public interface Extent extends InputExtent, OutputExtent { */ /** - * Returns the highest solid 'terrain' block. + * Returns the highest solid 'terrain' (movement-blocking) block. * * @param x the X coordinate * @param z the Z coordinate @@ -225,6 +225,9 @@ public interface Extent extends InputExtent, OutputExtent { * @return height of highest block found or 'minY' */ default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY) { + maxY = Math.min(maxY, getMaxY()); + minY = Math.max(getMinY(), minY); + for (int y = maxY; y >= minY; --y) { BlockState block = getBlock(x, y, z); if (block.getBlockType().getMaterial().isMovementBlocker()) { @@ -235,7 +238,7 @@ public interface Extent extends InputExtent, OutputExtent { } /** - * Returns the highest solid 'terrain' block. + * Returns the highest block matching the given mask. * * @param x the X coordinate * @param z the Z coordinate @@ -245,6 +248,9 @@ public interface Extent extends InputExtent, OutputExtent { * @return height of highest block found or 'minY' */ default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY, Mask filter) { + if (filter == null) { + return getHighestTerrainBlock(x, z, minY, maxY); + } maxY = Math.min(maxY, getMaxY()); minY = Math.max(getMinY(), minY); @@ -259,9 +265,7 @@ public interface Extent extends InputExtent, OutputExtent { } /** - * Returns the nearest surface layer (up/down from start) - *

    - * TODO: Someone understand this..? + * Returns the nearest surface layer (up/down from start), where a layer is 1/16th of a block to allow for snow, liquid, etc. * * @param x x to search from * @param z y to search from @@ -271,6 +275,9 @@ public interface Extent extends InputExtent, OutputExtent { * @return nearest surface layer */ default int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { + maxY = Math.min(maxY, getMaxY()); + minY = Math.max(getMinY(), minY); + int clearanceAbove = maxY - y; int clearanceBelow = y - minY; int clearance = Math.min(clearanceAbove, clearanceBelow); @@ -331,6 +338,9 @@ public interface Extent extends InputExtent, OutputExtent { * @return The y value of the nearest terrain block */ default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) { + maxY = Math.min(maxY, getMaxY()); + minY = Math.max(getMinY(), minY); + y = Math.max(minY, Math.min(maxY, y)); int clearanceAbove = maxY - y; int clearanceBelow = y - minY; @@ -438,6 +448,9 @@ public interface Extent extends InputExtent, OutputExtent { int failedMax, boolean ignoreAir ) { + maxY = Math.min(maxY, getMaxY()); + minY = Math.max(getMinY(), minY); + y = Math.max(minY, Math.min(maxY, y)); int clearanceAbove = maxY - y; int clearanceBelow = y - minY; @@ -494,7 +507,7 @@ public interface Extent extends InputExtent, OutputExtent { default void addSchems(Region region, Mask mask, List clipboards, int rarity, boolean rotate) throws WorldEditException { - spawnResource(region, new SchemGen(mask, this, clipboards, rotate), rarity, 1); + spawnResource(region, new SchemGen(mask, this, clipboards, rotate, region), rarity, 1); } default void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException { From 8c3df594132650ffbed1c2c1f86439629df9bf6a Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 25 Jul 2024 21:05:16 +0200 Subject: [PATCH 333/466] fix: improve schematic format selection (#2838) - no longer allow selecting a format specifically because of the generic extension `.schem` --- .../worldedit/command/SchematicCommands.java | 12 ++--- .../clipboard/io/BuiltInClipboardFormat.java | 45 +++++++++++++++++++ .../extent/clipboard/io/ClipboardFormat.java | 7 +++ .../extent/clipboard/io/ClipboardFormats.java | 43 +++++++++++++++++- .../src/main/resources/lang/strings.json | 1 + 5 files changed, 101 insertions(+), 7 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 8a7751bd4..e6a369502 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 @@ -376,11 +376,13 @@ public class SchematicCommands { actor.print(Caption.of("fawe.error.no-perm", "worldedit.schematic.load.other")); return; } - if (noExplicitFormat && filename.matches(".*\\.[\\w].*")) { - format = ClipboardFormats - .findByExtension(filename.substring(filename.lastIndexOf('.') + 1)); - } else { + if (!noExplicitFormat) { format = ClipboardFormats.findByAlias(formatName); + } else if (filename.matches(".*\\.[\\w].*")) { + format = ClipboardFormats + .findByExplicitExtension(filename.substring(filename.lastIndexOf('.') + 1)); + } else { + format = null; } file = MainUtil.resolve(dir, filename, format, false); } @@ -396,7 +398,7 @@ public class SchematicCommands { .isInSubDirectory(saveDir, file)) + ")")); return; } - if (format == null || noExplicitFormat) { + if (format == null) { format = ClipboardFormats.findByFile(file); if (format == null) { actor.print(Caption.of("worldedit.schematic.unknown-format", TextComponent.of(formatName))); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java index bfd6b2029..a26e7c99a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java @@ -50,6 +50,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Collections; import java.util.Locale; import java.util.Set; import java.util.zip.GZIPInputStream; @@ -125,6 +126,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { public String getPrimaryFileExtension() { return "schem"; } + + @Override + public Set getExplicitFileExtensions() { + return Set.of("schem3", "sponge3", "fast3"); + } }, FAST_V2("fast.2", "fawe.2", "schem.2") { @Override @@ -168,6 +174,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { } return super.isFormat(file); } + + @Override + public Set getExplicitFileExtensions() { + return Set.of("schem2", "sponge2", "fast2"); + } }, //FAWE end @@ -217,6 +228,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { } return rootEntry.value().value().containsKey("Materials"); } + + @Override + public Set getExplicitFileExtensions() { + return Set.of("mcedit", "schem1", "sponge1", "fast1"); + } }, SPONGE_V1_SCHEMATIC("sponge.1") { @Override @@ -243,6 +259,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { public boolean isFormat(File file) { return MCEDIT_SCHEMATIC.isFormat(file); } + + @Override + public Set getExplicitFileExtensions() { + return Collections.emptySet(); + } }, /** @@ -277,6 +298,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { public boolean isFormat(File file) { return FAST_V2.isFormat(file); } + + @Override + public Set getExplicitFileExtensions() { + return Collections.emptySet(); + } }, SPONGE_V3_SCHEMATIC("sponge.3", "slow", "safe") { // FAWE - edit aliases for fast @@ -301,6 +327,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { return FAST_V3.isFormat(file); //FAWE end } + + @Override + public Set getExplicitFileExtensions() { + return Collections.emptySet(); + } }, //FAWE start - recover schematics with bad entity data & register other clipboard formats BROKENENTITY("brokenentity", "legacyentity", "le", "be", "brokenentities", "legacyentities") { @@ -341,6 +372,10 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { return false; } + @Override + public Set getExplicitFileExtensions() { + return Collections.emptySet(); + } }, /** @@ -401,6 +436,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { public boolean isFormat(final File file) { return file.getName().toLowerCase(Locale.ROOT).endsWith(".nbt") && super.isFormat(file); } + + @Override + public Set getExplicitFileExtensions() { + return Set.of("nbt"); + } }, /** @@ -427,6 +467,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { public String getPrimaryFileExtension() { return "png"; } + + @Override + public Set getExplicitFileExtensions() { + return Set.of("png"); + } }; //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java index 7b4b1bf3b..cb1b97e2a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java @@ -124,6 +124,13 @@ public interface ClipboardFormat { //FAWE start + /** + * Get the explicit file extensions (e.g. .schem2) this format is commonly known to use. + * + * @return The explicit file extensions this format might be known by + */ + Set getExplicitFileExtensions(); + /** * Sets the actor's clipboard. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java index b69a7a0cc..786af54fa 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java @@ -66,6 +66,7 @@ public class ClipboardFormats { private static final Map aliasMap = new HashMap<>(); // FAWE start - keep order of ClipboardFormat entries -> prefer FAST over SPONGE_SCHEMATIC private static final Multimap fileExtensionMap = Multimaps.newMultimap(new HashMap<>(), LinkedHashSet::new); + private static final Multimap explicitFileExtensionMap = Multimaps.newMultimap(new HashMap<>(), LinkedHashSet::new); // FAWE end private static final List registeredFormats = new ArrayList<>(); @@ -86,6 +87,10 @@ public class ClipboardFormats { String lowExt = ext.toLowerCase(Locale.ROOT); fileExtensionMap.put(lowExt, format); } + for (String ext : format.getExplicitFileExtensions()) { + String lowExt = ext.toLowerCase(Locale.ROOT); + explicitFileExtensionMap.put(lowExt, format); + } registeredFormats.add(format); } @@ -147,6 +152,18 @@ public class ClipboardFormats { return fileExtensionMap.keySet().toArray(new String[fileExtensionMap.keySet().size()]); } + //FAWE start + + /** + * A mapping from explicit extensions (e.g. .schem2) to formats. + * + * @return a multimap from a file extension to the potential matching formats. + */ + public static Multimap getExplicitFileExtensionMap() { + return Multimaps.unmodifiableMultimap(explicitFileExtensionMap); + } + //FAWE end + private ClipboardFormats() { } @@ -157,8 +174,10 @@ public class ClipboardFormats { * * @param extension the extension * @return the format, otherwise null if one cannot be detected + * @deprecated DO NOT USE. Sponge formats 2 and 3 both use .schem by default. */ @Nullable + @Deprecated(forRemoval = true, since = "TODO") public static ClipboardFormat findByExtension(String extension) { checkNotNull(extension); @@ -172,6 +191,26 @@ public class ClipboardFormats { } + /** + * Detect the format given an explicit extension, e.g. ".schem2" + * + * @param extension the extension + * @return the format, otherwise null if one cannot be detected + */ + @Nullable + public static ClipboardFormat findByExplicitExtension(String extension) { + checkNotNull(extension); + + Collection> entries = getExplicitFileExtensionMap().entries(); + for (Map.Entry entry : entries) { + if (entry.getKey().equalsIgnoreCase(extension)) { + return entry.getValue(); + } + } + return null; + + } + public static MultiClipboardHolder loadAllFromInput( Actor player, String input, @@ -231,7 +270,7 @@ public class ClipboardFormats { } if (format == null && input.matches(".*\\.[\\w].*")) { String extension = input.substring(input.lastIndexOf('.') + 1); - format = findByExtension(extension); + format = findByExplicitExtension(extension); } f = MainUtil.resolve(dir, input, format, true); } @@ -302,7 +341,7 @@ public class ClipboardFormats { byte[] buffer = new byte[8192]; while ((entry = zip.getNextEntry()) != null) { String filename = entry.getName(); - ClipboardFormat format = findByExtension(filename); + ClipboardFormat format = findByExtension(filename); // FIXME if (format != null) { FastByteArrayOutputStream out = new FastByteArrayOutputStream(); int len; diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index 16e10a00d..7d49114b5 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -68,6 +68,7 @@ "fawe.worldedit.schematic.schematic.loaded": "{0} loaded. Paste it with //paste", "fawe.worldedit.schematic.schematic.saved": "{0} saved.", "fawe.worldedit.schematic.schematic.none": "No files found.", + "fawe.worldedit.schematic.schematic.load-failure": "File could not be read or it does not exist: {0}. If you are specifying a format, you may not be specifying the correct one. Sponge schematic v2 and v3 both use the .schem file extension. To allow FAWE to select the format, do not specify one.", "fawe.worldedit.clipboard.clipboard.uri.not.found": "You do not have {0} loaded", "fawe.worldedit.clipboard.clipboard.cleared": "Clipboard cleared", "fawe.worldedit.clipboard.clipboard.invalid.format": "Unknown clipboard format: {0}", From dac7cdbe4b7bc77b9c4c0d9e677cdb83ae17ebb2 Mon Sep 17 00:00:00 2001 From: Jordan Date: Sat, 27 Jul 2024 10:34:10 +0200 Subject: [PATCH 334/466] chore: deprecate FaweApi#load for clipboards as it does not allow closing (#2852) --- .../src/main/java/com/fastasyncworldedit/core/FaweAPI.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java index acc0d8bf3..0bf621bc6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java @@ -116,7 +116,10 @@ public class FaweAPI { * @param file the file to load * @return a clipboard containing the schematic * @see ClipboardFormat + * @deprecated Opens streams that are not then closed. Use {@link ClipboardFormats#findByFile(File)} and its relevant + * methods to allow closing created streams/closing the reader (which will close the stream(s)) */ + @Deprecated(forRemoval = true, since = "TODO") public static Clipboard load(File file) throws IOException { return ClipboardFormats.findByFile(file).load(file); } From 6fb0102e85621e0ff88fecee7352205c101cacd5 Mon Sep 17 00:00:00 2001 From: Jordan Date: Sat, 27 Jul 2024 10:34:25 +0200 Subject: [PATCH 335/466] feat: add litematica error when failing to load schematic (#2850) * feat: add litematica error when failing to load schematic * Adjust --- .../core/extent/clipboard/io/FastSchematicReaderV2.java | 2 +- .../java/com/sk89q/worldedit/command/SchematicCommands.java | 3 +++ worldedit-core/src/main/resources/lang/strings.json | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV2.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV2.java index 97fdd1f27..4c71a9f66 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV2.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV2.java @@ -247,7 +247,7 @@ public class FastSchematicReaderV2 extends NBTSchematicReader { throw new IOException("This schematic version is not supported; Version: " + version + ", DataVersion: " + dataVersion + ". It's very likely your schematic has an invalid file extension," + " if the schematic has been created on a version lower than 1.13.2, the extension MUST be `.schematic`," + - " elsewise the schematic can't be read properly."); + " elsewise the schematic can't be read properly. If you are using a litematica schematic, it is not supported!"); } if (blocks != null) { 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 e6a369502..2d75b65b8 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 @@ -421,6 +421,9 @@ public class SchematicCommands { } catch (URISyntaxException | IOException e) { actor.print(Caption.of("worldedit.schematic.file-not-exist", TextComponent.of(Objects.toString(e.getMessage())))); LOGGER.warn("Failed to load a saved clipboard", e); + } catch (Exception e) { + actor.print(Caption.of("fawe.worldedit.schematic.schematic.load-failure", TextComponent.of(e.getMessage()))); + LOGGER.error("Error loading a schematic", e); } finally { if (in != null) { try { diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index 7d49114b5..a56d98695 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -68,7 +68,7 @@ "fawe.worldedit.schematic.schematic.loaded": "{0} loaded. Paste it with //paste", "fawe.worldedit.schematic.schematic.saved": "{0} saved.", "fawe.worldedit.schematic.schematic.none": "No files found.", - "fawe.worldedit.schematic.schematic.load-failure": "File could not be read or it does not exist: {0}. If you are specifying a format, you may not be specifying the correct one. Sponge schematic v2 and v3 both use the .schem file extension. To allow FAWE to select the format, do not specify one.", + "fawe.worldedit.schematic.schematic.load-failure": "File could not be read or it does not exist: {0}. If you are specifying a format, you may not be specifying the correct one. Sponge schematic v2 and v3 both use the .schem file extension. To allow FAWE to select the format, do not specify one. If you are using a litematica schematic, it is not supported!", "fawe.worldedit.clipboard.clipboard.uri.not.found": "You do not have {0} loaded", "fawe.worldedit.clipboard.clipboard.cleared": "Clipboard cleared", "fawe.worldedit.clipboard.clipboard.invalid.format": "Unknown clipboard format: {0}", @@ -360,7 +360,7 @@ "worldedit.schematic.unknown-format": "Unknown schematic format: {0}.", "worldedit.schematic.load.does-not-exist": "Schematic {0} does not exist!", "worldedit.schematic.load.loading": "(Please wait... loading schematic.)", - "worldedit.schematic.load.unsupported-version": "This schematic is not supported. Version: {0}.", + "worldedit.schematic.load.unsupported-version": "This schematic is not supported. Version: {0}. If you are using a litematica schematic, it is not supported!", "worldedit.schematic.save.already-exists": "That schematic already exists. Use the -f flag to overwrite it.", "worldedit.schematic.save.failed-directory": "Could not create folder for schematics!", "worldedit.schematic.save.saving": "(Please wait... saving schematic.)", From 6052fc3128410ec5dc9c2703b497082b8647d22c Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 28 Jul 2024 09:53:20 +0200 Subject: [PATCH 336/466] feat: improve fawe limits (#2773) - add FaweLimit implementations for increasing concurrency levels - allow FaweLimit to perform processing (and forcefully disable as required) to capture [tile] entities - Use `BlockVector3#set(Extent orDefault)` where appropriate to reduce block checks - fixes #2679 - fixes #1874 --- .../fastasyncworldedit/core/FaweCache.java | 11 +- .../platform/binding/EditSessionHolder.java | 7 + .../platform/binding/ProvideBindings.java | 34 ++- .../core/extent/LimitExtent.java | 208 ++++++++++-------- .../extent/filter/block/CharFilterBlock.java | 5 +- .../core/function/mask/ABlockMask.java | 2 +- .../core/function/mask/DataMask.java | 4 +- .../core/function/mask/IdMask.java | 4 +- .../function/mask/SingleBlockStateMask.java | 2 +- .../core/function/mask/SplatterBrushMask.java | 2 +- .../core/limit/ConcurrentFaweLimit.java | 201 +++++++++++++++++ .../core/limit/FaweLimit.java | 65 ++++-- .../core/limit/ProcessorFaweLimit.java | 135 ++++++++++++ .../core/queue/IBatchProcessor.java | 2 +- .../java/com/sk89q/worldedit/EditSession.java | 11 +- .../sk89q/worldedit/EditSessionBuilder.java | 16 +- .../com/sk89q/worldedit/LocalSession.java | 17 +- .../worldedit/command/BiomeCommands.java | 2 + .../worldedit/command/BrushCommands.java | 6 +- .../worldedit/command/ClipboardCommands.java | 3 + .../worldedit/command/GenerationCommands.java | 19 +- .../worldedit/command/HistoryCommands.java | 3 + .../worldedit/command/RegionCommands.java | 18 ++ .../command/SnapshotUtilCommands.java | 2 + .../worldedit/command/UtilityCommands.java | 62 ++---- .../worldedit/command/tool/AreaPickaxe.java | 2 +- .../command/tool/BlockDataCyler.java | 2 +- .../worldedit/command/tool/BlockReplacer.java | 2 +- .../worldedit/command/tool/BrushTool.java | 2 +- .../command/tool/FloatingTreeRemover.java | 2 +- .../worldedit/command/tool/FloodFillTool.java | 2 +- .../command/tool/LongRangeBuildTool.java | 4 +- .../command/tool/RecursivePickaxe.java | 2 +- .../worldedit/command/tool/SinglePickaxe.java | 2 +- .../worldedit/command/tool/StackTool.java | 2 +- .../worldedit/command/tool/TreePlanter.java | 2 +- .../worldedit/command/tool/brush/Brush.java | 11 + .../util/annotation/ConfirmHandler.java | 2 +- .../util/annotation/PreloadHandler.java | 2 +- .../SynchronousSettingExpected.java | 22 ++ .../command/util/annotation/package-info.java | 1 + .../platform/PlatformCommandManager.java | 23 +- .../worldedit/function/mask/BiomeMask.java | 2 +- .../function/mask/BlockCategoryMask.java | 2 +- .../worldedit/function/mask/BlockMask.java | 2 +- .../function/mask/BlockStateMask.java | 2 +- .../function/mask/BlockTypeMask.java | 2 +- .../function/mask/ExistingBlockMask.java | 2 +- .../mask/InverseSingleBlockStateMask.java | 2 +- .../src/main/resources/lang/strings.json | 2 + 50 files changed, 706 insertions(+), 236 deletions(-) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/EditSessionHolder.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/ConcurrentFaweLimit.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/ProcessorFaweLimit.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/SynchronousSettingExpected.java diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java index 526570296..3ed494298 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java @@ -192,17 +192,22 @@ public enum FaweCache implements Trimable { Type.OUTSIDE_REGION ); public static final FaweException MAX_CHECKS = new FaweException( - Caption.of("fawe.cancel.reason.max" + ".checks"), + Caption.of("fawe.cancel.reason.max.checks"), + Type.MAX_CHECKS, + true + ); + public static final FaweException MAX_FAILS = new FaweException( + Caption.of("fawe.cancel.reason.max.fails"), Type.MAX_CHECKS, true ); public static final FaweException MAX_CHANGES = new FaweException( - Caption.of("fawe.cancel.reason.max" + ".changes"), + Caption.of("fawe.cancel.reason.max.changes"), Type.MAX_CHANGES, false ); public static final FaweException LOW_MEMORY = new FaweException( - Caption.of("fawe.cancel.reason.low" + ".memory"), + Caption.of("fawe.cancel.reason.low.memory"), Type.LOW_MEMORY, false ); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/EditSessionHolder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/EditSessionHolder.java new file mode 100644 index 000000000..1fd588ec4 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/EditSessionHolder.java @@ -0,0 +1,7 @@ +package com.fastasyncworldedit.core.extension.platform.binding; + +import com.sk89q.worldedit.EditSession; + +public record EditSessionHolder(EditSession session) { + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java index bc1e2bfbf..3e38b1724 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java @@ -3,7 +3,11 @@ package com.fastasyncworldedit.core.extension.platform.binding; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.database.DBHandler; import com.fastasyncworldedit.core.database.RollbackDatabase; +import com.fastasyncworldedit.core.extent.LimitExtent; +import com.fastasyncworldedit.core.extent.processor.ExtentBatchProcessorHolder; +import com.fastasyncworldedit.core.internal.exception.FaweException; import com.fastasyncworldedit.core.regions.FaweMaskManager; +import com.fastasyncworldedit.core.util.ExtentTraverser; import com.fastasyncworldedit.core.util.TextureUtil; import com.fastasyncworldedit.core.util.image.ImageUtil; import com.sk89q.worldedit.EditSession; @@ -11,6 +15,7 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.command.util.annotation.AllowedRegion; +import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.platform.Actor; @@ -25,6 +30,7 @@ import org.enginehub.piston.inject.Key; import org.enginehub.piston.util.ValueProvider; import java.awt.image.BufferedImage; +import java.lang.reflect.Method; import java.net.URI; import java.util.Optional; @@ -52,11 +58,33 @@ public class ProvideBindings extends Bindings { @Binding public EditSession editSession(LocalSession localSession, Actor actor, InjectedValueAccess context) { + Method commandMethod = + context.injectedValue(Key.of(InjectedValueStore.class)).get().injectedValue(Key.of(Method.class)).get(); + Arguments arguments = context.injectedValue(Key.of(Arguments.class)).orElse(null); String command = arguments == null ? null : arguments.get(); - EditSession editSession = localSession.createEditSession(actor, command); - editSession.enableStandardMode(); - Request.request().setEditSession(editSession); + boolean synchronousSetting = commandMethod.getAnnotation(SynchronousSettingExpected.class) != null; + EditSessionHolder holder = context.injectedValue(Key.of(EditSessionHolder.class)).orElse(null); + EditSession editSession = holder != null ? holder.session() : null; + if (editSession == null) { + editSession = localSession.createEditSession(actor, command, synchronousSetting); + editSession.enableStandardMode(); + } else { + LimitExtent limitExtent = new ExtentTraverser<>(editSession).findAndGet(LimitExtent.class); + if (limitExtent != null) { + limitExtent.setProcessing(!synchronousSetting); + if (!synchronousSetting) { + ExtentBatchProcessorHolder processorHolder = new ExtentTraverser<>(editSession).findAndGet( + ExtentBatchProcessorHolder.class); + if (processorHolder != null) { + processorHolder.addProcessor(limitExtent); + } else { + throw new FaweException(Caption.of("fawe.error.no-process-non-synchronous-edit")); + } + } + } + Request.request().setEditSession(editSession); + } return editSession; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java index d02ff9320..33f19bfaa 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java @@ -1,11 +1,17 @@ package com.fastasyncworldedit.core.extent; import com.fastasyncworldedit.core.extent.filter.block.ExtentFilterBlock; -import com.fastasyncworldedit.core.function.generator.GenBase; -import com.fastasyncworldedit.core.function.generator.Resource; +import com.fastasyncworldedit.core.extent.processor.ProcessorScope; import com.fastasyncworldedit.core.internal.exception.FaweException; +import com.fastasyncworldedit.core.limit.ConcurrentFaweLimit; import com.fastasyncworldedit.core.limit.FaweLimit; +import com.fastasyncworldedit.core.limit.ProcessorFaweLimit; import com.fastasyncworldedit.core.queue.Filter; +import com.fastasyncworldedit.core.queue.IBatchProcessor; +import com.fastasyncworldedit.core.queue.IChunk; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import com.fastasyncworldedit.core.util.ExtentTraverser; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEditException; @@ -17,7 +23,6 @@ import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.formatting.text.Component; @@ -37,18 +42,22 @@ import java.util.Set; import java.util.UUID; import java.util.function.Consumer; -public class LimitExtent extends AbstractDelegateExtent { +public class LimitExtent extends AbstractDelegateExtent implements IBatchProcessor { private final FaweLimit limit; private final boolean[] faweExceptionReasonsUsed = new boolean[FaweException.Type.values().length]; private final Consumer onErrorMessage; + private final int chunk_size; + private boolean processing; /** * Create a new instance. * * @param extent the extent * @param limit the limit + * @deprecated Use {@link LimitExtent#LimitExtent(Extent, FaweLimit, Consumer, boolean, boolean)} */ + @Deprecated(forRemoval = true, since = "TODO") public LimitExtent(Extent extent, FaweLimit limit) { this(extent, limit, c -> { }); @@ -60,11 +69,41 @@ public class LimitExtent extends AbstractDelegateExtent { * @param extent the extent * @param limit the limit * @param onErrorMessage consumer to handle a component generated by exceptions + * @deprecated Use {@link LimitExtent#LimitExtent(Extent, FaweLimit, Consumer, boolean, boolean)} */ + @Deprecated(forRemoval = true, since = "TODO") public LimitExtent(Extent extent, FaweLimit limit, Consumer onErrorMessage) { + this(extent, limit, onErrorMessage, false, false); + } + + /** + * Create a new instance. + * + * @param extent the extent + * @param limit the limit + * @param onErrorMessage consumer to handle a component generated by exceptions + * @param processing if this limit extent is expected to be processing + * @param expectSynchronousSetting if synchronous block setting is expected + * @since TODO + */ + public LimitExtent( + Extent extent, + FaweLimit limit, + Consumer onErrorMessage, + boolean processing, + boolean expectSynchronousSetting + ) { super(extent); - this.limit = limit; + if (!expectSynchronousSetting) { + this.limit = new ConcurrentFaweLimit(limit); + } else if (processing) { + this.limit = new ProcessorFaweLimit(limit); + } else { + this.limit = limit; + } this.onErrorMessage = onErrorMessage; + this.chunk_size = 16 * 16 * (extent.getMaxY() - extent.getMinY()); + this.processing = !expectSynchronousSetting; } private void handleException(FaweException e) { @@ -81,7 +120,7 @@ public class LimitExtent extends AbstractDelegateExtent { public List getEntities(Region region) { limit.THROW_MAX_CHECKS(region.getVolume()); try { - return super.getEntities(region); + return extent.getEntities(region); } catch (FaweException e) { handleException(e); return Collections.emptyList(); @@ -92,7 +131,7 @@ public class LimitExtent extends AbstractDelegateExtent { public List getEntities() { limit.THROW_MAX_CHECKS(); try { - return super.getEntities(); + return extent.getEntities(); } catch (FaweException e) { handleException(e); return Collections.emptyList(); @@ -105,7 +144,7 @@ public class LimitExtent extends AbstractDelegateExtent { limit.THROW_MAX_CHANGES(); limit.THROW_MAX_ENTITIES(); try { - return super.createEntity(location, entity); + return extent.createEntity(location, entity); } catch (FaweException e) { handleException(e); return null; @@ -118,7 +157,7 @@ public class LimitExtent extends AbstractDelegateExtent { limit.THROW_MAX_CHANGES(); limit.THROW_MAX_ENTITIES(); try { - return super.createEntity(location, entity, uuid); + return extent.createEntity(location, entity, uuid); } catch (FaweException e) { handleException(e); return null; @@ -130,7 +169,7 @@ public class LimitExtent extends AbstractDelegateExtent { limit.THROW_MAX_CHANGES(); limit.THROW_MAX_ENTITIES(); try { - super.removeEntity(x, y, z, uuid); + extent.removeEntity(x, y, z, uuid); } catch (FaweException e) { handleException(e); } @@ -138,9 +177,9 @@ public class LimitExtent extends AbstractDelegateExtent { @Override public boolean regenerateChunk(int x, int z, @Nullable BiomeType type, @Nullable Long seed) { - limit.THROW_MAX_CHANGES(Character.MAX_VALUE); + limit.THROW_MAX_CHANGES(chunk_size); try { - return super.regenerateChunk(x, z, type, seed); + return extent.regenerateChunk(x, z, type, seed); } catch (FaweException e) { handleException(e); return false; @@ -151,7 +190,7 @@ public class LimitExtent extends AbstractDelegateExtent { public int getHighestTerrainBlock(int x, int z, int minY, int maxY) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return super.getHighestTerrainBlock(x, z, minY, maxY); + return extent.getHighestTerrainBlock(x, z, minY, maxY); } catch (FaweException e) { handleException(e); return minY; @@ -162,7 +201,7 @@ public class LimitExtent extends AbstractDelegateExtent { public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return super.getHighestTerrainBlock(x, z, minY, maxY, filter); + return extent.getHighestTerrainBlock(x, z, minY, maxY, filter); } catch (FaweException e) { handleException(e); return minY; @@ -173,7 +212,7 @@ public class LimitExtent extends AbstractDelegateExtent { public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return super.getNearestSurfaceLayer(x, z, y, minY, maxY); + return extent.getNearestSurfaceLayer(x, z, y, minY, maxY); } catch (FaweException e) { handleException(e); return minY; @@ -184,7 +223,7 @@ public class LimitExtent extends AbstractDelegateExtent { public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir); + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir); } catch (FaweException e) { handleException(e); return minY; @@ -195,7 +234,7 @@ public class LimitExtent extends AbstractDelegateExtent { public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY); + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY); } catch (FaweException e) { handleException(e); return minY; @@ -206,7 +245,7 @@ public class LimitExtent extends AbstractDelegateExtent { public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax); + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax); } catch (FaweException e) { handleException(e); return minY; @@ -217,7 +256,7 @@ public class LimitExtent extends AbstractDelegateExtent { public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask); + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask); } catch (FaweException e) { handleException(e); return minY; @@ -237,91 +276,47 @@ public class LimitExtent extends AbstractDelegateExtent { ) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir); + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir); } catch (FaweException e) { handleException(e); return minY; } } - @Override - public void addCaves(Region region) throws WorldEditException { - limit.THROW_MAX_CHECKS(region.getVolume()); - limit.THROW_MAX_CHANGES(region.getVolume()); - super.addCaves(region); - } - - @Override - public void generate(Region region, GenBase gen) throws WorldEditException { - limit.THROW_MAX_CHECKS(region.getVolume()); - limit.THROW_MAX_CHANGES(region.getVolume()); - super.generate(region, gen); - } - - @Override - public void addSchems(Region region, Mask mask, List clipboards, int rarity, boolean rotate) throws - WorldEditException { - limit.THROW_MAX_CHECKS(region.getVolume()); - limit.THROW_MAX_CHANGES(region.getVolume()); - super.addSchems(region, mask, clipboards, rarity, rotate); - } - - @Override - public void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException { - limit.THROW_MAX_CHECKS(region.getVolume()); - limit.THROW_MAX_CHANGES(region.getVolume()); - super.spawnResource(region, gen, rarity, frequency); - } - - @Override - public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws - WorldEditException { - limit.THROW_MAX_CHECKS(region.getVolume()); - limit.THROW_MAX_CHANGES(region.getVolume()); - super.addOre(region, mask, material, size, frequency, rarity, minY, maxY); - } - - @Override - public void addOres(Region region, Mask mask) throws WorldEditException { - limit.THROW_MAX_CHECKS(region.getVolume()); - limit.THROW_MAX_CHANGES(region.getVolume()); - super.addOres(region, mask); - } - @Override public List> getBlockDistribution(Region region) { limit.THROW_MAX_CHECKS(region.getVolume()); - return super.getBlockDistribution(region); + return extent.getBlockDistribution(region); } @Override public List> getBlockDistributionWithData(Region region) { limit.THROW_MAX_CHECKS(region.getVolume()); - return super.getBlockDistributionWithData(region); + return extent.getBlockDistributionWithData(region); } @Override public int countBlocks(Region region, Set searchBlocks) { limit.THROW_MAX_CHECKS(region.getVolume()); - return super.countBlocks(region, searchBlocks); + return extent.countBlocks(region, searchBlocks); } @Override public int countBlocks(Region region, Mask searchMask) { limit.THROW_MAX_CHECKS(region.getVolume()); - return super.countBlocks(region, searchMask); + return extent.countBlocks(region, searchMask); } @Override public > int setBlocks(Region region, B block) throws MaxChangedBlocksException { limit.THROW_MAX_CHANGES(region.getVolume()); - return super.setBlocks(region, block); + return extent.setBlocks(region, block); } @Override public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException { limit.THROW_MAX_CHANGES(region.getVolume()); - return super.setBlocks(region, pattern); + return extent.setBlocks(region, pattern); } @Override @@ -329,41 +324,34 @@ public class LimitExtent extends AbstractDelegateExtent { MaxChangedBlocksException { limit.THROW_MAX_CHECKS(region.getVolume()); limit.THROW_MAX_CHANGES(region.getVolume()); - return super.replaceBlocks(region, filter, replacement); + return extent.replaceBlocks(region, filter, replacement); } @Override public int replaceBlocks(Region region, Set filter, Pattern pattern) throws MaxChangedBlocksException { limit.THROW_MAX_CHECKS(region.getVolume()); limit.THROW_MAX_CHANGES(region.getVolume()); - return super.replaceBlocks(region, filter, pattern); + return extent.replaceBlocks(region, filter, pattern); } @Override public int replaceBlocks(Region region, Mask mask, Pattern pattern) throws MaxChangedBlocksException { limit.THROW_MAX_CHECKS(region.getVolume()); limit.THROW_MAX_CHANGES(region.getVolume()); - return super.replaceBlocks(region, mask, pattern); - } - - @Override - public int center(Region region, Pattern pattern) throws MaxChangedBlocksException { - limit.THROW_MAX_CHECKS(region.getVolume()); - limit.THROW_MAX_CHANGES(region.getVolume()); - return super.center(region, pattern); + return extent.replaceBlocks(region, mask, pattern); } @Override public int setBlocks(Set vset, Pattern pattern) { limit.THROW_MAX_CHANGES(vset.size()); - return super.setBlocks(vset, pattern); + return extent.setBlocks(vset, pattern); } @Override public T apply(Region region, T filter, boolean full) { limit.THROW_MAX_CHECKS(region.getVolume()); limit.THROW_MAX_CHANGES(region.getVolume()); - return super.apply(region, filter, full); + return extent.apply(region, filter, full); } @Override @@ -393,14 +381,14 @@ public class LimitExtent extends AbstractDelegateExtent { } limit.THROW_MAX_CHECKS(size); limit.THROW_MAX_CHANGES(size); - return super.apply(positions, filter); + return extent.apply(positions, filter); } @Override public BlockState getBlock(BlockVector3 position) { limit.THROW_MAX_CHECKS(); try { - return super.getBlock(position); + return extent.getBlock(position); } catch (FaweException e) { handleException(e); return BlockTypes.AIR.getDefaultState(); @@ -411,7 +399,7 @@ public class LimitExtent extends AbstractDelegateExtent { public BlockState getBlock(int x, int y, int z) { limit.THROW_MAX_CHECKS(); try { - return super.getBlock(x, y, z); + return extent.getBlock(x, y, z); } catch (FaweException e) { handleException(e); return BlockTypes.AIR.getDefaultState(); @@ -422,7 +410,7 @@ public class LimitExtent extends AbstractDelegateExtent { public BaseBlock getFullBlock(BlockVector3 position) { limit.THROW_MAX_CHECKS(); try { - return super.getFullBlock(position); + return extent.getFullBlock(position); } catch (FaweException e) { handleException(e); return BlockTypes.AIR.getDefaultState().toBaseBlock(); @@ -433,7 +421,7 @@ public class LimitExtent extends AbstractDelegateExtent { public BaseBlock getFullBlock(int x, int y, int z) { limit.THROW_MAX_CHECKS(); try { - return super.getFullBlock(x, y, z); + return extent.getFullBlock(x, y, z); } catch (FaweException e) { handleException(e); return BlockTypes.AIR.getDefaultState().toBaseBlock(); @@ -444,7 +432,7 @@ public class LimitExtent extends AbstractDelegateExtent { public BiomeType getBiome(BlockVector3 position) { limit.THROW_MAX_CHECKS(); try { - return super.getBiome(position); + return extent.getBiome(position); } catch (FaweException e) { handleException(e); return BiomeTypes.FOREST; @@ -455,7 +443,7 @@ public class LimitExtent extends AbstractDelegateExtent { public BiomeType getBiomeType(int x, int y, int z) { limit.THROW_MAX_CHECKS(); try { - return super.getBiomeType(x, y, z); + return extent.getBiomeType(x, y, z); } catch (FaweException e) { handleException(e); return BiomeTypes.FOREST; @@ -470,7 +458,7 @@ public class LimitExtent extends AbstractDelegateExtent { limit.THROW_MAX_BLOCKSTATES(); } try { - return super.setBlock(position, block); + return extent.setBlock(position, block); } catch (FaweException e) { handleException(e); return false; @@ -484,7 +472,7 @@ public class LimitExtent extends AbstractDelegateExtent { limit.THROW_MAX_BLOCKSTATES(); } try { - return super.setBlock(x, y, z, block); + return extent.setBlock(x, y, z, block); } catch (FaweException e) { handleException(e); return false; @@ -494,9 +482,9 @@ public class LimitExtent extends AbstractDelegateExtent { @Override public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { limit.THROW_MAX_CHANGES(); - limit.MAX_BLOCKSTATES(); + limit.THROW_MAX_BLOCKSTATES(); try { - return super.setTile(x, y, z, tile); + return extent.setTile(x, y, z, tile); } catch (FaweException e) { handleException(e); return false; @@ -507,7 +495,7 @@ public class LimitExtent extends AbstractDelegateExtent { public boolean setBiome(BlockVector3 position, BiomeType biome) { limit.THROW_MAX_CHANGES(); try { - return super.setBiome(position, biome); + return extent.setBiome(position, biome); } catch (FaweException e) { handleException(e); return false; @@ -518,11 +506,41 @@ public class LimitExtent extends AbstractDelegateExtent { public boolean setBiome(int x, int y, int z, BiomeType biome) { limit.THROW_MAX_CHANGES(); try { - return super.setBiome(x, y, z, biome); + return extent.setBiome(x, y, z, biome); } catch (FaweException e) { handleException(e); return false; } } + public void setProcessing(boolean processing) { + this.processing = processing; + } + + @Override + public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { + if (!processing) { + return set; + } + int tiles = set.getTiles().size(); + int ents = set.getEntities().size() + set.getEntityRemoves().size(); + limit.THROW_MAX_CHANGES(tiles + ents); + limit.THROW_MAX_BLOCKSTATES(tiles); + limit.THROW_MAX_ENTITIES(ents); + return set; + } + + @Override + public Extent construct(final Extent child) { + if (extent != child) { + new ExtentTraverser(this).setNext(child); + } + return this; + } + + @Override + public ProcessorScope getScope() { + return ProcessorScope.READING_SET_BLOCKS; + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java index 579f04a9a..f569ff0bb 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java @@ -170,10 +170,13 @@ public class CharFilterBlock extends ChunkFilterBlock { @Override public synchronized final void filter(Filter filter) { + initSet(); for (y = 0, index = 0; y < 16; y++) { for (z = 0; z < 16; z++) { for (x = 0; x < 16; x++, index++) { - filter.applyBlock(this); + if (setArr[index] != BlockTypesCache.ReservedIDs.__RESERVED__) { + filter.applyBlock(this); + } } } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ABlockMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ABlockMask.java index 7fdebdded..ed5b028dd 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ABlockMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ABlockMask.java @@ -26,7 +26,7 @@ public abstract class ABlockMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - return test(getExtent().getBlock(vector)); + return test(vector.getBlock(getExtent())); } public abstract boolean test(BlockState state); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/DataMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/DataMask.java index 2b3ad7edb..84b8f77ad 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/DataMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/DataMask.java @@ -16,9 +16,9 @@ public class DataMask extends AbstractExtentMask implements ResettableMask { @Override public boolean test(BlockVector3 vector) { if (data != -1) { - return getExtent().getBlock(vector).getInternalPropertiesId() == data; + return vector.getBlock(getExtent()).getInternalPropertiesId() == data; } else { - data = getExtent().getBlock(vector).getInternalPropertiesId(); + data = vector.getBlock(getExtent()).getInternalPropertiesId(); return true; } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/IdMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/IdMask.java index 49c90183a..b0ba4fb59 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/IdMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/IdMask.java @@ -24,7 +24,9 @@ public class IdMask extends AbstractExtentMask implements ResettableMask { @Override public boolean test(BlockVector3 vector) { - return test(getExtent(), vector); + int blockID = vector.getBlock(getExtent()).getInternalBlockTypeId(); + int testId = id.compareAndExchange(-1, blockID); + return blockID == testId || testId == -1; } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SingleBlockStateMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SingleBlockStateMask.java index 32d853bda..400f32163 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SingleBlockStateMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SingleBlockStateMask.java @@ -30,7 +30,7 @@ public class SingleBlockStateMask extends ABlockMask { @Override public boolean test(BlockVector3 vector) { - int test = getExtent().getBlock(vector).getOrdinal(); + int test = vector.getBlock(getExtent()).getOrdinal(); return ordinal == test || isAir && test == 0; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SplatterBrushMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SplatterBrushMask.java index 250969616..d80399be4 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SplatterBrushMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SplatterBrushMask.java @@ -40,7 +40,7 @@ public class SplatterBrushMask extends AbstractExtentMask { double dist = vector.distanceSq(position); synchronized (placed) { if (dist < size2 && !placed.contains(vector) && ThreadLocalRandom.current().nextInt(5) < 2 && surface.test(vector)) { - placed.add(vector); + placed.add(vector.toImmutable()); return true; } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/ConcurrentFaweLimit.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/ConcurrentFaweLimit.java new file mode 100644 index 000000000..91ec1621d --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/ConcurrentFaweLimit.java @@ -0,0 +1,201 @@ +package com.fastasyncworldedit.core.limit; + +import com.fastasyncworldedit.core.FaweCache; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +/** + * Allows concurrent limit calculations + * + * @since TODO + */ +public class ConcurrentFaweLimit extends FaweLimit { + + public AtomicLong ATOMIC_MAX_CHANGES = new AtomicLong(); + public AtomicInteger ATOMIC_MAX_FAILS = new AtomicInteger(); + public AtomicLong ATOMIC_MAX_CHECKS = new AtomicLong(); + public AtomicInteger ATOMIC_MAX_ITERATIONS = new AtomicInteger(); + public AtomicInteger ATOMIC_MAX_BLOCKSTATES = new AtomicInteger(); + public AtomicInteger ATOMIC_MAX_ENTITIES = new AtomicInteger(); + + public ConcurrentFaweLimit(FaweLimit other) { + set(other); + } + + @Override + public boolean MAX_CHANGES() { + return ATOMIC_MAX_CHANGES.decrementAndGet() < 0; + } + + @Override + public boolean MAX_FAILS() { + return ATOMIC_MAX_FAILS.decrementAndGet() < 0; + } + + @Override + public boolean MAX_CHECKS() { + return ATOMIC_MAX_CHECKS.decrementAndGet() < 0; + } + + @Override + public boolean MAX_ITERATIONS() { + return ATOMIC_MAX_ITERATIONS.decrementAndGet() < 0; + } + + @Override + public boolean MAX_BLOCKSTATES() { + return ATOMIC_MAX_BLOCKSTATES.decrementAndGet() < 0; + } + + @Override + public boolean MAX_ENTITIES() { + return ATOMIC_MAX_ENTITIES.decrementAndGet() < 0; + } + + @Override + public void THROW_MAX_CHANGES() { + if (ATOMIC_MAX_CHANGES.decrementAndGet() < 0) { + throw FaweCache.MAX_CHANGES; + } + } + + @Override + public void THROW_MAX_FAILS() { + if (ATOMIC_MAX_FAILS.decrementAndGet() < 0) { + throw FaweCache.MAX_FAILS; + } + } + + @Override + public void THROW_MAX_CHECKS() { + if (ATOMIC_MAX_CHECKS.decrementAndGet() < 0) { + throw FaweCache.MAX_CHECKS; + } + } + + @Override + public void THROW_MAX_ITERATIONS() { + if (ATOMIC_MAX_ITERATIONS.decrementAndGet() < 0) { + throw FaweCache.MAX_ITERATIONS; + } + } + + @Override + public void THROW_MAX_BLOCKSTATES() { + if (ATOMIC_MAX_BLOCKSTATES.decrementAndGet() < 0) { + throw FaweCache.MAX_TILES; + } + } + + @Override + public void THROW_MAX_ENTITIES() { + if (ATOMIC_MAX_ENTITIES.decrementAndGet() < 0) { + throw FaweCache.MAX_ENTITIES; + } + } + + @Override + public void THROW_MAX_CHANGES(int amt) { + if (amt == 0) { + return; + } + if (ATOMIC_MAX_CHANGES.addAndGet(-amt) < 0) { + throw FaweCache.MAX_CHANGES; + } + } + + @Override + public void THROW_MAX_CHANGES(long amt) { + if (amt == 0) { + return; + } + if (ATOMIC_MAX_CHANGES.addAndGet(-amt) < 0) { + throw FaweCache.MAX_CHANGES; + } + } + + @Override + public void THROW_MAX_FAILS(int amt) { + if (amt == 0) { + return; + } + if (ATOMIC_MAX_FAILS.addAndGet(-amt) < 0) { + throw FaweCache.MAX_FAILS; + } + } + + @Override + public void THROW_MAX_CHECKS(int amt) { + if (amt == 0) { + return; + } + if (ATOMIC_MAX_CHECKS.addAndGet(-amt) < 0) { + throw FaweCache.MAX_CHECKS; + } + } + + @Override + public void THROW_MAX_CHECKS(long amt) { + if (amt == 0) { + return; + } + if (ATOMIC_MAX_CHECKS.addAndGet(-amt) < 0) { + throw FaweCache.MAX_CHECKS; + } + } + + @Override + public void THROW_MAX_ITERATIONS(int amt) { + if (amt == 0) { + return; + } + if (ATOMIC_MAX_ITERATIONS.addAndGet(-amt) < 0) { + throw FaweCache.MAX_ITERATIONS; + } + } + + @Override + public void THROW_MAX_BLOCKSTATES(int amt) { + if (amt == 0) { + return; + } + if (ATOMIC_MAX_BLOCKSTATES.addAndGet(-amt) < 0) { + throw FaweCache.MAX_TILES; + } + } + + @Override + public void THROW_MAX_ENTITIES(int amt) { + if (amt == 0) { + return; + } + if (ATOMIC_MAX_ENTITIES.addAndGet(-amt) < 0) { + throw FaweCache.MAX_ENTITIES; + } + } + + @Override + public void set(FaweLimit other) { + super.set(other); + ATOMIC_MAX_CHANGES.set(other.MAX_CHANGES); + ATOMIC_MAX_FAILS.set(other.MAX_FAILS); + ATOMIC_MAX_CHECKS.set(other.MAX_CHECKS); + ATOMIC_MAX_ITERATIONS.set(other.MAX_ITERATIONS); + ATOMIC_MAX_BLOCKSTATES.set(other.MAX_BLOCKSTATES); + ATOMIC_MAX_ENTITIES.set(other.MAX_ENTITIES); + } + + @Override + public FaweLimit getLimitUsed(FaweLimit originalLimit) { + FaweLimit newLimit = new FaweLimit(); + newLimit.MAX_CHANGES = originalLimit.MAX_CHANGES - this.ATOMIC_MAX_CHANGES.get(); + newLimit.MAX_FAILS = originalLimit.MAX_FAILS - this.ATOMIC_MAX_FAILS.get(); + newLimit.MAX_CHECKS = originalLimit.MAX_CHECKS - this.ATOMIC_MAX_CHECKS.get(); + newLimit.MAX_ITERATIONS = originalLimit.MAX_ITERATIONS - this.ATOMIC_MAX_ITERATIONS.get(); + newLimit.MAX_BLOCKSTATES = originalLimit.MAX_BLOCKSTATES - this.ATOMIC_MAX_BLOCKSTATES.get(); + newLimit.MAX_ENTITIES = originalLimit.MAX_ENTITIES - this.ATOMIC_MAX_ENTITIES.get(); + return newLimit; + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java index d17787f03..f7a99dd35 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java @@ -1,6 +1,7 @@ package com.fastasyncworldedit.core.limit; import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.internal.exception.FaweException; import com.fastasyncworldedit.core.configuration.Settings; import java.util.Collections; @@ -9,12 +10,12 @@ import java.util.Set; public class FaweLimit { public int MAX_ACTIONS = 0; - public long MAX_CHANGES = 0; - public int MAX_FAILS = 0; - public long MAX_CHECKS = 0; - public int MAX_ITERATIONS = 0; - public int MAX_BLOCKSTATES = 0; - public int MAX_ENTITIES = 0; + public volatile long MAX_CHANGES = 0; + public volatile int MAX_FAILS = 0; + public volatile long MAX_CHECKS = 0; + public volatile int MAX_ITERATIONS = 0; + public volatile int MAX_BLOCKSTATES = 0; + public volatile int MAX_ENTITIES = 0; public int MAX_HISTORY = 0; public int SCHEM_FILE_SIZE_LIMIT = 0; public int SCHEM_FILE_NUM_LIMIT = 0; @@ -161,85 +162,85 @@ public class FaweLimit { return MAX_ENTITIES-- > 0; } - public void THROW_MAX_CHANGES() { + public void THROW_MAX_CHANGES() throws FaweException { if (MAX_CHANGES-- <= 0) { throw FaweCache.MAX_CHANGES; } } - public void THROW_MAX_FAILS() { + public void THROW_MAX_FAILS() throws FaweException { if (MAX_FAILS-- <= 0) { - throw FaweCache.MAX_CHECKS; + throw FaweCache.MAX_FAILS; } } - public void THROW_MAX_CHECKS() { + public void THROW_MAX_CHECKS() throws FaweException { if (MAX_CHECKS-- <= 0) { throw FaweCache.MAX_CHECKS; } } - public void THROW_MAX_ITERATIONS() { + public void THROW_MAX_ITERATIONS() throws FaweException { if (MAX_ITERATIONS-- <= 0) { throw FaweCache.MAX_ITERATIONS; } } - public void THROW_MAX_BLOCKSTATES() { + public void THROW_MAX_BLOCKSTATES() throws FaweException { if (MAX_BLOCKSTATES-- <= 0) { throw FaweCache.MAX_TILES; } } - public void THROW_MAX_ENTITIES() { + public void THROW_MAX_ENTITIES() throws FaweException { if (MAX_ENTITIES-- <= 0) { throw FaweCache.MAX_ENTITIES; } } - public void THROW_MAX_CHANGES(int amt) { + public void THROW_MAX_CHANGES(int amt) throws FaweException { if ((MAX_CHANGES -= amt) <= 0) { throw FaweCache.MAX_CHANGES; } } - public void THROW_MAX_CHANGES(long amt) { + public void THROW_MAX_CHANGES(long amt) throws FaweException { if ((MAX_CHANGES -= amt) <= 0) { throw FaweCache.MAX_CHANGES; } } - public void THROW_MAX_FAILS(int amt) { + public void THROW_MAX_FAILS(int amt) throws FaweException { if ((MAX_FAILS -= amt) <= 0) { - throw FaweCache.MAX_CHECKS; + throw FaweCache.MAX_FAILS; } } - public void THROW_MAX_CHECKS(int amt) { + public void THROW_MAX_CHECKS(int amt) throws FaweException { if ((MAX_CHECKS -= amt) <= 0) { throw FaweCache.MAX_CHECKS; } } - public void THROW_MAX_CHECKS(long amt) { + public void THROW_MAX_CHECKS(long amt) throws FaweException { if ((MAX_CHECKS -= amt) <= 0) { throw FaweCache.MAX_CHECKS; } } - public void THROW_MAX_ITERATIONS(int amt) { + public void THROW_MAX_ITERATIONS(int amt) throws FaweException { if ((MAX_ITERATIONS -= amt) <= 0) { throw FaweCache.MAX_ITERATIONS; } } - public void THROW_MAX_BLOCKSTATES(int amt) { + public void THROW_MAX_BLOCKSTATES(int amt) throws FaweException { if ((MAX_BLOCKSTATES -= amt) <= 0) { throw FaweCache.MAX_TILES; } } - public void THROW_MAX_ENTITIES(int amt) { + public void THROW_MAX_ENTITIES(int amt) throws FaweException { if ((MAX_ENTITIES -= amt) <= 0) { throw FaweCache.MAX_ENTITIES; } @@ -270,6 +271,22 @@ public class FaweLimit { && MAX_BUTCHER_RADIUS == Integer.MAX_VALUE; } + /** + * Get an {@link FaweLimit} representing the amount of a limit used from a given "original" limit + * + * @since TODO + */ + public FaweLimit getLimitUsed(FaweLimit originalLimit) { + FaweLimit newLimit = new FaweLimit(); + newLimit.MAX_CHANGES = originalLimit.MAX_CHANGES - this.MAX_CHANGES; + newLimit.MAX_FAILS = originalLimit.MAX_FAILS - this.MAX_FAILS; + newLimit.MAX_CHECKS = originalLimit.MAX_CHECKS - this.MAX_CHECKS; + newLimit.MAX_ITERATIONS = originalLimit.MAX_ITERATIONS - this.MAX_ITERATIONS; + newLimit.MAX_BLOCKSTATES = originalLimit.MAX_BLOCKSTATES - this.MAX_BLOCKSTATES; + newLimit.MAX_ENTITIES = originalLimit.MAX_ENTITIES - this.MAX_ENTITIES; + return newLimit; + } + public void set(FaweLimit limit) { MAX_ACTIONS = limit.MAX_ACTIONS; MAX_CHANGES = limit.MAX_CHANGES; @@ -331,4 +348,8 @@ public class FaweLimit { return MAX_CHANGES + ""; } + public ProcessorFaweLimit toConcurrent() { + return new ProcessorFaweLimit(this); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/ProcessorFaweLimit.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/ProcessorFaweLimit.java new file mode 100644 index 000000000..47c97a78b --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/ProcessorFaweLimit.java @@ -0,0 +1,135 @@ +package com.fastasyncworldedit.core.limit; + +import com.fastasyncworldedit.core.FaweCache; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +/** + * Allows concurrent limit calculations for THROW_MAX_XXX(amount) methods. Other methods use the default implementations in + * {@link FaweLimit} + * + * @since TODO + */ +public class ProcessorFaweLimit extends FaweLimit { + + public AtomicLong ATOMIC_MAX_CHANGES = new AtomicLong(); + public AtomicInteger ATOMIC_MAX_FAILS = new AtomicInteger(); + public AtomicLong ATOMIC_MAX_CHECKS = new AtomicLong(); + public AtomicInteger ATOMIC_MAX_ITERATIONS = new AtomicInteger(); + public AtomicInteger ATOMIC_MAX_BLOCKSTATES = new AtomicInteger(); + public AtomicInteger ATOMIC_MAX_ENTITIES = new AtomicInteger(); + + public ProcessorFaweLimit(FaweLimit other) { + set(other); + } + + @Override + public void THROW_MAX_CHANGES(int amt) { + if (amt == 0) { + return; + } + final long changes = MAX_CHANGES; + if (ATOMIC_MAX_CHANGES.updateAndGet(i -> (MAX_CHANGES = Math.min(i, changes) - amt)) < 0) { + throw FaweCache.MAX_CHANGES; + } + } + + @Override + public void THROW_MAX_CHANGES(long amt) { + if (amt == 0) { + return; + } + final long changes = MAX_CHANGES; + if (ATOMIC_MAX_CHANGES.updateAndGet(i -> (MAX_CHANGES = Math.min(i, changes) - amt))< 0) { + throw FaweCache.MAX_CHANGES; + } + } + + @Override + public void THROW_MAX_FAILS(int amt) { + if (amt == 0) { + return; + } + final int fails = MAX_FAILS; + if (ATOMIC_MAX_FAILS.updateAndGet(i -> (MAX_FAILS = Math.min(i, fails) - amt)) < 0) { + throw FaweCache.MAX_FAILS; + } + } + + @Override + public void THROW_MAX_CHECKS(int amt) { + final long checks = MAX_CHECKS; + if (ATOMIC_MAX_CHECKS.updateAndGet(i -> (MAX_CHECKS = Math.min(i, checks) - amt)) < 0) { + throw FaweCache.MAX_CHECKS; + } + } + + @Override + public void THROW_MAX_CHECKS(long amt) { + if (amt == 0) { + return; + } + final long checks = MAX_CHECKS; + if (ATOMIC_MAX_CHECKS.updateAndGet(i -> (MAX_CHECKS = Math.min(i, checks) - amt)) < 0) { + throw FaweCache.MAX_CHECKS; + } + } + + @Override + public void THROW_MAX_ITERATIONS(int amt) { + if (amt == 0) { + return; + } + final int iterations = MAX_ITERATIONS; + if (ATOMIC_MAX_ITERATIONS.updateAndGet(i -> (MAX_ITERATIONS = Math.min(i, iterations) - amt)) < 0) { + throw FaweCache.MAX_ITERATIONS; + } + } + + @Override + public void THROW_MAX_BLOCKSTATES(int amt) { + if (amt == 0) { + return; + } + final int states = MAX_BLOCKSTATES; + if (ATOMIC_MAX_BLOCKSTATES.updateAndGet(i -> (MAX_BLOCKSTATES = Math.min(i, states) - amt)) < 0) { + throw FaweCache.MAX_TILES; + } + } + + @Override + public void THROW_MAX_ENTITIES(int amt) { + if (amt == 0) { + return; + } + final int entities = MAX_ENTITIES; + if (ATOMIC_MAX_ENTITIES.updateAndGet(i -> (MAX_ENTITIES = Math.min(i, entities) - amt)) < 0) { + throw FaweCache.MAX_ENTITIES; + } + } + + @Override + public void set(FaweLimit other) { + super.set(other); + ATOMIC_MAX_CHANGES.set(other.MAX_CHANGES); + ATOMIC_MAX_FAILS.set(other.MAX_FAILS); + ATOMIC_MAX_CHECKS.set(other.MAX_CHECKS); + ATOMIC_MAX_ITERATIONS.set(other.MAX_ITERATIONS); + ATOMIC_MAX_BLOCKSTATES.set(other.MAX_BLOCKSTATES); + ATOMIC_MAX_ENTITIES.set(other.MAX_ENTITIES); + } + + @Override + public FaweLimit getLimitUsed(FaweLimit originalLimit) { + FaweLimit newLimit = new FaweLimit(); + newLimit.MAX_CHANGES = originalLimit.MAX_CHANGES - Math.min(this.ATOMIC_MAX_CHANGES.get(), MAX_CHANGES); + newLimit.MAX_FAILS = originalLimit.MAX_FAILS - Math.min(this.ATOMIC_MAX_FAILS.get(), MAX_FAILS); + newLimit.MAX_CHECKS = originalLimit.MAX_CHECKS - Math.min(this.ATOMIC_MAX_CHECKS.get(), MAX_CHECKS); + newLimit.MAX_ITERATIONS = originalLimit.MAX_ITERATIONS - Math.min(this.ATOMIC_MAX_ITERATIONS.get(), MAX_ITERATIONS); + newLimit.MAX_BLOCKSTATES = originalLimit.MAX_BLOCKSTATES - Math.min(this.ATOMIC_MAX_BLOCKSTATES.get(), MAX_BLOCKSTATES); + newLimit.MAX_ENTITIES = originalLimit.MAX_ENTITIES - Math.min(this.ATOMIC_MAX_ENTITIES.get(), MAX_ENTITIES); + return newLimit; + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java index 4ba91a4f3..6a5473979 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java @@ -50,7 +50,7 @@ public interface IBatchProcessor { } /** - * Convert this processor into an Extent based processor instead of a queue batch based on. + * Convert this processor into an Extent based processor instead of a queue batch based one. */ @Nullable Extent construct(Extent child); 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 926265bfb..7bc243134 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -308,16 +308,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { * @return Limit remaining */ public FaweLimit getLimitUsed() { - FaweLimit newLimit = new FaweLimit(); - newLimit.MAX_ACTIONS = originalLimit.MAX_ACTIONS - limit.MAX_ACTIONS; - newLimit.MAX_CHANGES = originalLimit.MAX_CHANGES - limit.MAX_CHANGES; - newLimit.MAX_FAILS = originalLimit.MAX_FAILS - limit.MAX_FAILS; - newLimit.MAX_CHECKS = originalLimit.MAX_CHECKS - limit.MAX_CHECKS; - newLimit.MAX_ITERATIONS = originalLimit.MAX_ITERATIONS - limit.MAX_ITERATIONS; - newLimit.MAX_BLOCKSTATES = originalLimit.MAX_BLOCKSTATES - limit.MAX_BLOCKSTATES; - newLimit.MAX_ENTITIES = originalLimit.MAX_ENTITIES - limit.MAX_ENTITIES; - newLimit.MAX_HISTORY = limit.MAX_HISTORY; - return newLimit; + return originalLimit.getLimitUsed(limit); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java index ca6f3b6a5..5cf0cf745 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java @@ -104,6 +104,7 @@ public final class EditSessionBuilder { private Extent extent; private boolean compiled; private boolean wrapped; + private boolean expectSynchronousSetting = false; private @Nullable World world; @@ -415,6 +416,15 @@ public final class EditSessionBuilder { return setDirty(); } + public EditSessionBuilder expectSynchronousSetting(boolean expectSynchronousSetting) { + this.expectSynchronousSetting = expectSynchronousSetting; + return setDirty(); + } + + public boolean isExpectingSynchronousSetting() { + return this.expectSynchronousSetting; + } + /** * Compile the builder to the settings given. Prepares history, limits, lighting, etc. */ @@ -635,7 +645,11 @@ public final class EditSessionBuilder { }; } if (limit != null && !limit.isUnlimited()) { - this.extent = new LimitExtent(this.extent, limit, onErrorMessage); + this.extent = new LimitExtent(this.extent, limit, onErrorMessage, placeChunks && combineStages, expectSynchronousSetting); + // Only process if we're not necessarily going to catch tiles via Extent#setBlock, e.g. because using PQE methods + if (placeChunks && combineStages && !expectSynchronousSetting) { + queue.addProcessor((LimitExtent) this.extent); + } } this.extent = wrapExtent(this.extent, eventBus, event, EditSession.Stage.BEFORE_HISTORY); } 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 48e2a8078..aa5f51e57 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -1725,10 +1725,25 @@ public class LocalSession implements TextureHolder { * @return an edit session */ public EditSession createEditSession(Actor actor) { + //FAWE start return createEditSession(actor, null); } public EditSession createEditSession(Actor actor, String command) { + return createEditSession(actor, command, false); + } + + /** + * Construct a new edit session. + * + * @param actor the actor + * @param command the command executed resulting in the creation of the edit session + * @param expectSynchronousSetting if it is expected that blocks will only be set synchronously, i.e. from one thread (at a + * time) + * @return an edit session + * @since TODO + */ + public EditSession createEditSession(Actor actor, String command, boolean expectSynchronousSetting) { checkNotNull(actor); World world = null; @@ -1739,7 +1754,6 @@ public class LocalSession implements TextureHolder { } // Create an edit session - //FAWE start - we don't use the edit session builder yet EditSession editSession; EditSessionBuilder builder = WorldEdit.getInstance().newEditSessionBuilder().world(world); if (actor.isPlayer() && actor instanceof Player) { @@ -1749,6 +1763,7 @@ public class LocalSession implements TextureHolder { } builder.command(command); builder.fastMode(!this.sideEffectSet.doesApplyAny()); + builder.expectSynchronousSetting(expectSynchronousSetting); editSession = builder.build(); 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 a60968da1..1f551aefa 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 @@ -30,6 +30,7 @@ import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.command.util.annotation.Confirm; import com.sk89q.worldedit.command.util.annotation.Preload; +import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; @@ -179,6 +180,7 @@ public class BiomeCommands { ) @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected // TODO improve using filter/chunk-based-placement @Confirm(Confirm.Processor.REGION) @CommandPermissions("worldedit.biome.set") public void setBiome( 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 664e656c4..8f1733fbb 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 @@ -992,15 +992,15 @@ public class BrushCommands { Expression radius, @Arg(desc = "Command to run") List input, - @Switch(name = 'p', desc = "Show any printed output") - boolean print + @Switch(name = 'h', desc = "Hide any printed output") + boolean hide ) throws WorldEditException { worldEdit.checkMaxBrushRadius( radius, context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) ); String cmd = StringMan.join(input, " "); - set(context, new CommandBrush(cmd, print), "worldedit.brush.command").setSize(radius); + set(context, new CommandBrush(cmd, !hide), "worldedit.brush.command").setSize(radius); } @Command( 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 378449755..a8fa5076e 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 @@ -47,6 +47,7 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.annotation.Confirm; import com.sk89q.worldedit.command.util.annotation.Preload; +import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; @@ -438,6 +439,7 @@ public class ClipboardCommands { desc = "Place the clipboard's contents without applying transformations (e.g. rotate)" ) @CommandPermissions("worldedit.clipboard.place") + @SynchronousSettingExpected @Logging(PLACEMENT) public void place( Actor actor, World world, LocalSession session, final EditSession editSession, @@ -502,6 +504,7 @@ public class ClipboardCommands { desc = "Paste the clipboard's contents" ) @CommandPermissions("worldedit.clipboard.paste") + @SynchronousSettingExpected @Logging(PLACEMENT) public void paste( Actor actor, World world, LocalSession session, EditSession editSession, 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 4b2f98e0c..f2a3c80ed 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 @@ -38,6 +38,7 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.annotation.Confirm; import com.sk89q.worldedit.command.util.annotation.Preload; +import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.mask.Mask; @@ -104,6 +105,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.cylinder") @Logging(PLACEMENT) + @SynchronousSettingExpected public int hcyl( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") @@ -152,6 +154,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.cylinder") @Logging(PLACEMENT) + @SynchronousSettingExpected public int cyl( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") @@ -197,6 +200,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.cone") @Logging(PLACEMENT) + @SynchronousSettingExpected public int cone(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") Pattern pattern, @@ -243,6 +247,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.sphere") @Logging(PLACEMENT) + @SynchronousSettingExpected public int hsphere( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") @@ -262,6 +267,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.sphere") @Logging(PLACEMENT) + @SynchronousSettingExpected public int sphere( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") @@ -313,6 +319,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.forest") @Logging(POSITION) + @SynchronousSettingExpected public int forestGen( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The size of the forest, in blocks", def = "10") @@ -337,6 +344,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.pumpkins") @Logging(POSITION) + @SynchronousSettingExpected public int pumpkins( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The size of the patch", def = "10") @@ -357,6 +365,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.pyramid") @Logging(PLACEMENT) + @SynchronousSettingExpected public int hollowPyramid( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to set") @@ -373,6 +382,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.pyramid") @Logging(PLACEMENT) + @SynchronousSettingExpected public int pyramid( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to set") @@ -400,6 +410,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.shape") @Logging(ALL) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int generate( Actor actor, LocalSession session, EditSession editSession, @@ -486,6 +497,7 @@ public class GenerationCommands { @CommandPermissions("worldedit.generation.shape.biome") @Logging(ALL) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int generateBiome( Actor actor, LocalSession session, EditSession editSession, @@ -564,6 +576,7 @@ public class GenerationCommands { @CommandPermissions("worldedit.generation.caves") @Logging(PLACEMENT) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public void caves( Actor actor, LocalSession session, EditSession editSession, @Selection Region region, @@ -602,6 +615,7 @@ public class GenerationCommands { @CommandPermissions("worldedit.generation.ore") @Logging(PLACEMENT) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public void ores( Actor actor, @@ -621,6 +635,7 @@ public class GenerationCommands { desc = "Generate an image" ) @CommandPermissions("worldedit.generation.image") + @SynchronousSettingExpected @Logging(PLACEMENT) public void image( Actor actor, @@ -685,6 +700,7 @@ public class GenerationCommands { @CommandPermissions("worldedit.generation.ore") @Logging(PLACEMENT) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public void ore( Actor actor, @@ -719,8 +735,9 @@ public class GenerationCommands { desc = "Creates a distorted sphere" ) @Logging(PLACEMENT) + @SynchronousSettingExpected @CommandPermissions("worldedit.generation.blob") - public int blobBrush( + public int blob( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "Pattern") Pattern pattern, 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 d1a647587..ba736e45e 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 @@ -27,6 +27,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.annotation.Confirm; +import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.inventory.BlockBag; @@ -61,6 +62,7 @@ public class HistoryCommands { desc = "Undoes the last action (from history)" ) @CommandPermissions({"worldedit.history.undo", "worldedit.history.undo.self"}) + @SynchronousSettingExpected public void undo( Actor actor, LocalSession session, @Confirm(Confirm.Processor.LIMIT) @Arg(desc = "Number of undoes to perform", def = "1") @@ -108,6 +110,7 @@ public class HistoryCommands { desc = "Redoes the last action (from history)" ) @CommandPermissions({"worldedit.history.redo", "worldedit.history.redo.self"}) + @SynchronousSettingExpected public void redo( Actor actor, LocalSession session, @Confirm(Confirm.Processor.LIMIT) @Arg(desc = "Number of redoes to perform", def = "1") 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 6a121aa02..ac3490cca 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 @@ -35,6 +35,7 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.annotation.Confirm; import com.sk89q.worldedit.command.util.annotation.Preload; +import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.GroundFunction; @@ -225,6 +226,7 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.line") @Logging(REGION) + @SynchronousSettingExpected public int line( Actor actor, EditSession editSession, @Selection Region region, @@ -257,6 +259,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.curve") @Logging(REGION) @Confirm(Confirm.Processor.REGION) + @SynchronousSettingExpected public int curve( Actor actor, EditSession editSession, @Selection Region region, @@ -315,6 +318,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.overlay") @Logging(REGION) @Confirm(Confirm.Processor.REGION) + @SynchronousSettingExpected // TODO improve using filter/chunk-based-placement public int overlay( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to overlay") @@ -333,6 +337,7 @@ public class RegionCommands { @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) @Confirm(Confirm.Processor.REGION) + @SynchronousSettingExpected // TODO improve using filter/chunk-based-placement public void lay( Actor actor, EditSession editSession, @@ -369,6 +374,7 @@ public class RegionCommands { ) @Logging(REGION) @CommandPermissions("worldedit.region.center") + @SynchronousSettingExpected public int center( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to set") @@ -386,6 +392,8 @@ public class RegionCommands { @CommandPermissions("worldedit.region.naturalize") @Logging(REGION) @Confirm(Confirm.Processor.REGION) + @SynchronousSettingExpected // TODO improve using filter/chunk-based-placement + @Preload(Preload.PreloadCheck.PRELOAD) public int naturalize(Actor actor, EditSession editSession, @Selection Region region) throws WorldEditException { int affected = editSession.naturalizeCuboidBlocks(region); actor.print(Caption.of("worldedit.naturalize.naturalized", TextComponent.of(affected))); @@ -437,6 +445,7 @@ public class RegionCommands { @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) @Confirm(Confirm.Processor.REGION) + @SynchronousSettingExpected public int smooth( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "# of iterations to perform", def = "1") @@ -510,6 +519,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.snowsmooth") @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int snowSmooth( Actor actor, EditSession editSession, @Selection Region region, @@ -536,6 +546,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.move") @Logging(ORIENTATION_REGION) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int move( Actor actor, World world, EditSession editSession, LocalSession session, @@ -599,6 +610,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.fall") @Logging(ORIENTATION_REGION) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public void fall( Actor actor, EditSession editSession, @@ -618,6 +630,7 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.stack") @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Logging(ORIENTATION_REGION) public int stack( Actor actor, World world, EditSession editSession, LocalSession session, @@ -683,6 +696,7 @@ public class RegionCommands { ) @CommandPermissions("worldedit.regen") @Logging(REGION) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) void regenerate( Actor actor, World world, LocalSession session, EditSession editSession, @@ -737,6 +751,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.deform") @Logging(ALL) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int deform( Actor actor, LocalSession session, EditSession editSession, @@ -814,6 +829,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.hollow") @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int hollow( Actor actor, EditSession editSession, @@ -848,6 +864,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.forest") @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int forest( Actor actor, EditSession editSession, @Selection Region region, @@ -869,6 +886,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.flora") @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int flora( Actor actor, EditSession editSession, @Selection Region region, 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 b98785631..074711521 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 @@ -28,6 +28,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.formatting.text.TextComponent; @@ -66,6 +67,7 @@ public class SnapshotUtilCommands { ) @Logging(REGION) @CommandPermissions("worldedit.snapshots.restore") + @SynchronousSettingExpected public void restore( Actor actor, World world, LocalSession session, EditSession editSession, @Arg(name = "snapshot", desc = "The snapshot to restore", def = "") 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 c81db21d8..c7c6ab9a1 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 @@ -44,6 +44,7 @@ import com.sk89q.worldedit.command.util.EntityRemover; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.PrintCommandHelp; import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; +import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; @@ -220,6 +221,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.fill") @Logging(PLACEMENT) + @SynchronousSettingExpected public int fill( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The blocks to fill with") @@ -311,6 +313,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.fill.recursive") @Logging(PLACEMENT) + @SynchronousSettingExpected public int fillr( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The blocks to fill with") @@ -343,6 +346,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.drain") @Logging(PLACEMENT) + @SynchronousSettingExpected public int drain( Actor actor, LocalSession session, EditSession editSession, //FAWE start - we take an expression over a double @@ -373,6 +377,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.fixlava") @Logging(PLACEMENT) + @SynchronousSettingExpected public int fixLava( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius to fix in") @@ -394,6 +399,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.fixwater") @Logging(PLACEMENT) + @SynchronousSettingExpected public int fixWater( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius to fix in") @@ -415,6 +421,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.removeabove") @Logging(PLACEMENT) + @SynchronousSettingExpected public int removeAbove( Actor actor, World world, LocalSession session, EditSession editSession, @Arg(desc = "The apothem of the square to remove from", def = "1") @@ -440,6 +447,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.removebelow") @Logging(PLACEMENT) + @SynchronousSettingExpected public int removeBelow( Actor actor, World world, LocalSession session, EditSession editSession, @Arg(desc = "The apothem of the square to remove from", def = "1") @@ -465,6 +473,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.removenear") @Logging(PLACEMENT) + @SynchronousSettingExpected public int removeNear( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The mask of blocks to remove") @@ -527,6 +536,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.snow") @Logging(PLACEMENT) + @SynchronousSettingExpected public int snow( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius of the cylinder to snow in", def = "10") @@ -566,6 +576,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.thaw") @Logging(PLACEMENT) + @SynchronousSettingExpected public int thaw( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius of the cylinder to thaw in", def = "10") @@ -595,6 +606,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.green") @Logging(PLACEMENT) + @SynchronousSettingExpected public int green( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius of the cylinder to convert in", def = "10") @@ -629,6 +641,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.extinguish") @Logging(PLACEMENT) + @SynchronousSettingExpected public int extinguish( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius of the square to remove in", def = "") @@ -843,55 +856,6 @@ public class UtilityCommands { } } -// @Command( -// name = "/hollowr", -// desc = "Hollow out a space recursively with a pattern" -// ) -// @CommandPermissions("worldedit.hollowr") -// @Logging(PLACEMENT) -// public int hollowr( -// Actor actor, -// LocalSession session, -// EditSession editSession, -// @Arg(desc = "The radius to hollow out") Expression radiusExp, -// @ArgFlag(name = 'p', desc = "The blocks to fill with") Pattern pattern, -// @ArgFlag(name = 'm', desc = "The blocks remove", def = "") Mask mask -// ) throws WorldEditException { -// //FAWE start -// double radius = radiusExp.evaluate(); -// //FAWE end -// radius = Math.max(1, radius); -// we.checkMaxRadius(radius); -// if (mask == null) { -// Mask mask = new MaskIntersection( -// new RegionMask(new EllipsoidRegion(null, origin, Vector3.at(radius, radius, radius))), -// new BoundedHeightMask( -// Math.max(lowerBound, minY), -// Math.min(maxY, origin.getBlockY()) -// ), -// Masks.negate(new ExistingBlockMask(this)) -// ); -// } -// -// // Want to replace blocks -// BlockReplace replace = new BlockReplace(this, pattern); -// -// // Pick how we're going to visit blocks -// RecursiveVisitor visitor; -// //FAWE start - provide extent for preloading, min/max y -// if (recursive) { -// visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), minY, maxY, this); -// } else { -// visitor = new DownwardVisitor(mask, replace, origin.getBlockY(), (int) (radius * 2 + 1), minY, maxY, this); -// } -// //FAWE end -// -// BlockVector3 pos = session.getPlacementPosition(actor); -// int affected = editSession.res(pos, pattern, radius, depth, true); -// actor.print(Caption.of("worldedit.fillr.created", TextComponent.of(affected))); -// return affected; -// } - public static List> filesToEntry(final File root, final List files, final UUID uuid) { return files.stream() .map(input -> { // Keep this functional, as transform is evaluated lazily 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 299908d99..e1996520a 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 @@ -64,7 +64,7 @@ public class AreaPickaxe implements BlockTool { return false; } - try (EditSession editSession = session.createEditSession(player, "AreaPickaxe")) { + try (EditSession editSession = session.createEditSession(player, "AreaPickaxe", true)) { editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop); int maxY = editSession.getMaxY(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java index 2d35b2226..304fb9e77 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java @@ -89,7 +89,7 @@ public class BlockDataCyler implements DoubleActionBlockTool { Property objProp = (Property) currentProperty; BaseBlock newBlock = block.with(objProp, currentProperty.getValues().get(index)); - try (EditSession editSession = session.createEditSession(player)) { + try (EditSession editSession = session.createEditSession(player, null, true)) { try { editSession.setBlock(blockPoint, newBlock); player.print(Caption.of( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java index 75ef200c6..957ed3d83 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java @@ -63,7 +63,7 @@ public class BlockReplacer implements DoubleActionBlockTool { ) { BlockBag bag = session.getBlockBag(player); - try (EditSession editSession = session.createEditSession(player)) { + try (EditSession editSession = session.createEditSession(player, null, true)) { try { BlockVector3 position = clicked.toVector().toBlockPoint(); editSession.setBlock(position, pattern); 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 6021102a2..74b06b1f5 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 @@ -440,7 +440,7 @@ public class BrushTool Caption.of("fawe.error.no-perm", StringMan.join(current.getPermissions(), ","))); return false; } - try (EditSession editSession = session.createEditSession(player, current.toString())) { + try (EditSession editSession = session.createEditSession(player, current.toString(), brush.setsSynchronously())) { Location target = player.getBlockTrace(getRange(), true, traceMask); if (target == null) { 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 385fcd2f3..81d755b8c 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 @@ -86,7 +86,7 @@ public class FloatingTreeRemover implements BlockTool { return true; } - try (EditSession editSession = session.createEditSession(player, "FloatingTreeRemover")) { + try (EditSession editSession = session.createEditSession(player, "FloatingTreeRemover", true)) { try { final Set blockSet = bfs(world, clicked.toVector().toBlockPoint()); if (blockSet == null) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java index 3d8d63f7d..6381e9356 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java @@ -82,7 +82,7 @@ public class FloodFillTool implements BlockTool { return true; } - try (EditSession editSession = session.createEditSession(player, "FloodFillTool")) { + try (EditSession editSession = session.createEditSession(player, "FloodFillTool", true)) { try { //FAWE start - Respect masks Mask mask = initialType.toMask(editSession); 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 9e60fdcf3..b1686ccd5 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 @@ -61,7 +61,7 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo } BlockBag bag = session.getBlockBag(player); - try (EditSession editSession = session.createEditSession(player, "LongRangeBuildTool")) { + try (EditSession editSession = session.createEditSession(player, "LongRangeBuildTool", true)) { try { BlockVector3 blockPoint = pos.toVector().toBlockPoint(); BaseBlock applied = secondary.applyBlock(blockPoint); @@ -90,7 +90,7 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo } BlockBag bag = session.getBlockBag(player); - try (EditSession editSession = session.createEditSession(player, "LongRangeBuildTool")) { + try (EditSession editSession = session.createEditSession(player, "LongRangeBuildTool", true)) { try { BlockVector3 blockPoint = pos.toVector().toBlockPoint(); BaseBlock applied = primary.applyBlock(blockPoint); 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 9fad39f9d..a8b666ff6 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 @@ -79,7 +79,7 @@ public class RecursivePickaxe implements BlockTool { return false; } - try (EditSession editSession = session.createEditSession(player, "RecursivePickaxe")) { + try (EditSession editSession = session.createEditSession(player, "RecursivePickaxe", true)) { editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop); //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java index b35865fb3..152f7016a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java @@ -62,7 +62,7 @@ public class SinglePickaxe implements BlockTool { return false; } - try (EditSession editSession = session.createEditSession(player)) { + try (EditSession editSession = session.createEditSession(player, null, true)) { try { editSession.getSurvivalExtent().setToolUse(config.superPickaxeDrop); editSession.setBlock(blockPoint, BlockTypes.AIR.getDefaultState()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/StackTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/StackTool.java index 614bbcf32..8aa5761f5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/StackTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/StackTool.java @@ -59,7 +59,7 @@ public class StackTool implements BlockTool { } BlockBag bag = session.getBlockBag(player); - try (EditSession editSession = session.createEditSession(player)) { + try (EditSession editSession = session.createEditSession(player, null, true)) { BlockStateHolder block = editSession.getFullBlock(clicked.toVector().toBlockPoint()); try { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java index 1f52ff103..b2f6ae7cf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java @@ -60,7 +60,7 @@ public class TreePlanter implements BlockTool { @Nullable Direction face ) { - try (EditSession editSession = session.createEditSession(player)) { + try (EditSession editSession = session.createEditSession(player, null, true)) { try { boolean successful = false; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java index 8efe2ab77..e38ae0d99 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java @@ -40,4 +40,15 @@ public interface Brush { */ void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException; + //FAWE start + /** + * If this brush is expected to set blocks synchronously, i.e. from one thread (at a time) + * + * @since TODO + */ + default boolean setsSynchronously() { + return true; + } + //FAWE end + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/ConfirmHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/ConfirmHandler.java index 067f9cfeb..5d6b66483 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/ConfirmHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/ConfirmHandler.java @@ -12,7 +12,7 @@ import java.lang.reflect.Method; import java.util.Optional; /** - * Logs called commands to a logger. + * Handles commands indicated as requiring confirmation. */ public class ConfirmHandler implements CommandCallListener { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/PreloadHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/PreloadHandler.java index 9e1dc106f..037c94e5b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/PreloadHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/PreloadHandler.java @@ -11,7 +11,7 @@ import java.lang.reflect.Method; import java.util.Optional; /** - * Logs called commands to a logger. + * Initialises preloading of chunks. */ public class PreloadHandler implements CommandCallListener { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/SynchronousSettingExpected.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/SynchronousSettingExpected.java new file mode 100644 index 000000000..3cc936fda --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/SynchronousSettingExpected.java @@ -0,0 +1,22 @@ +package com.sk89q.worldedit.command.util.annotation; + +import org.enginehub.piston.inject.InjectAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates it is expected that blocks will only be set synchronously, i.e. from one thread (at a time) + * + * @since TODO + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ + ElementType.METHOD +}) +@InjectAnnotation +public @interface SynchronousSettingExpected { + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/package-info.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/package-info.java index 006432a73..f7f293277 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/package-info.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/package-info.java @@ -8,6 +8,7 @@ * {@link com.sk89q.worldedit.command.util.annotation.PatternList}, * {@link com.sk89q.worldedit.command.util.annotation.Preload}, * {@link com.sk89q.worldedit.command.util.annotation.PreloadHandler}, + * {@link com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected}, * {@link com.sk89q.worldedit.command.util.annotation.Step}, * {@link com.sk89q.worldedit.command.util.annotation.Time} */ diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index b03e4ce54..65fc7c196 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -24,6 +24,7 @@ import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extension.platform.binding.Bindings; import com.fastasyncworldedit.core.extension.platform.binding.ConsumeBindings; +import com.fastasyncworldedit.core.extension.platform.binding.EditSessionHolder; import com.fastasyncworldedit.core.extension.platform.binding.PrimitiveBindings; import com.fastasyncworldedit.core.extension.platform.binding.ProvideBindings; import com.fastasyncworldedit.core.internal.command.MethodInjector; @@ -154,7 +155,6 @@ import org.enginehub.piston.inject.MemoizingValueAccess; import org.enginehub.piston.inject.MergedValueAccess; import org.enginehub.piston.part.SubCommandPart; import org.enginehub.piston.suggestion.Suggestion; -import org.enginehub.piston.util.HelpGenerator; import org.enginehub.piston.util.ValueProvider; import javax.annotation.Nonnull; @@ -227,7 +227,6 @@ public final class PlatformCommandManager { new ConfirmHandler(), new PreloadHandler() //FAWE end - )); // setup separate from main constructor // ensures that everything is definitely assigned @@ -312,20 +311,6 @@ public final class PlatformCommandManager { } ); //FAWE start - /* - globalInjectedValues.injectValue(Key.of(EditSession.class), - context -> { - LocalSession localSession = context.injectedValue(Key.of(LocalSession.class)) - .orElseThrow(() -> new IllegalStateException("No LocalSession")); - return context.injectedValue(Key.of(Actor.class)) - .map(actor -> { - EditSession editSession = localSession.createEditSession(actor); - editSession.enableStandardMode(); - Request.request().setEditSession(editSession); - return editSession; - }); - }); - */ // TODO: Ping @MattBDev to reimplement 2020-02-04 // globalInjectedValues.injectValue(Key.of(CFICommands.CFISettings.class), // context -> context.injectedValue(Key.of(Actor.class)) @@ -866,10 +851,10 @@ public final class PlatformCommandManager { store.injectValue(Key.of(InjectedValueStore.class), ValueProvider.constant(store)); store.injectValue(Key.of(Event.class), ValueProvider.constant(event)); //FAWE start - allow giving editsessions - if (event instanceof CommandEvent) { - EditSession session = ((CommandEvent) event).getSession(); + if (event instanceof CommandEvent commandEvent) { + EditSession session = commandEvent.getSession(); if (session != null) { - store.injectValue(Key.of(EditSession.class), context -> Optional.of(session)); + store.injectValue(Key.of(EditSessionHolder.class), context -> Optional.of(new EditSessionHolder(session))); } } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask.java index cd3ef56d5..ab919b35f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask.java @@ -94,7 +94,7 @@ public class BiomeMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - BiomeType biome = getExtent().getBiome(vector); + BiomeType biome = vector.getBiome(getExtent()); return biomes.contains(biome); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java index bad9781ea..a1b869efb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java @@ -46,7 +46,7 @@ public class BlockCategoryMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - return category.contains(getExtent().getBlock(vector)); + return category.contains(vector.getBlock(getExtent())); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java index 9f191a4cc..c7d3473f3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java @@ -204,7 +204,7 @@ public class BlockMask extends ABlockMask { @Override public boolean test(BlockVector3 vector) { - int test = getExtent().getBlock(vector).getOrdinal(); + int test = vector.getBlock(getExtent()).getOrdinal(); return ordinals[test] || replacesAir() && test == 0; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java index ac558520c..0c563cdf7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java @@ -56,7 +56,7 @@ public class BlockStateMask extends AbstractExtentMask { //FAWE start @Override public boolean test(BlockVector3 vector) { - return test(getExtent().getBlock(vector)); + return test(vector.getBlock(getExtent())); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java index 17f1419e5..c3567b6d5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java @@ -124,7 +124,7 @@ public class BlockTypeMask extends AbstractExtentMask { //FAWE start @Override public boolean test(BlockVector3 vector) { - return test(getExtent().getBlock(vector).getBlockType()); + return test(vector.getBlock(getExtent()).getBlockType()); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java index b75a4cd1e..be62c2eae 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java @@ -41,7 +41,7 @@ public class ExistingBlockMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - return !getExtent().getBlock(vector).getBlockType().getMaterial().isAir(); + return !vector.getBlock(getExtent()).getBlockType().getMaterial().isAir(); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java index e8b14b95a..6bb39b958 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java @@ -29,7 +29,7 @@ public class InverseSingleBlockStateMask extends ABlockMask { @Override public boolean test(BlockVector3 vector) { - int test = getExtent().getBlock(vector).getOrdinal(); + int test = vector.getBlock(getExtent()).getOrdinal(); if (isAir && test == 0) { return false; } diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index a56d98695..fea3e7dd5 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -141,6 +141,7 @@ "fawe.error.limit.max-brush-radius": "Maximum brush radius in limit: {0}", "fawe.error.limit.max-radius": "Maximum radius in limit: {0}", "fawe.error.no-valid-on-hotbar": "No valid block types on hotbar", + "fawe.error.no-process-non-synchronous-edit": "No processor holder was found but edit is non-synchronous", "fawe.cancel.count": "Cancelled {0} edits.", "fawe.cancel.reason.confirm": "Use //confirm to execute {0}", "fawe.cancel.reason.confirm.region": "Your selection is large ({0} -> {1}, containing {3} blocks). Use //confirm to execute {2}", @@ -151,6 +152,7 @@ "fawe.cancel.reason.low.memory": "Low memory", "fawe.cancel.reason.max.changes": "Too many blocks changed", "fawe.cancel.reason.max.checks": "Too many block checks", + "fawe.cancel.reason.max.fails": "Too many fails", "fawe.cancel.reason.max.tiles": "Too many block entities", "fawe.cancel.reason.max.entities": "Too many entities", "fawe.cancel.reason.max.iterations": "Max iterations", From d1f9d3d6d50a61c5199b23797880df32bfa9888f Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 28 Jul 2024 11:16:25 +0200 Subject: [PATCH 337/466] fix: improve FAWE stream history (#2844) - reset "origin"/relative X/Z when larger than short min/max value so we do not write incorrect positions - history size can be larger than int max value - fixes #2583 --- .../command/tool/brush/CopyPastaBrush.java | 2 +- .../core/database/RollbackDatabase.java | 48 ++++++++++++++----- .../history/changeset/AbstractChangeSet.java | 2 +- .../changeset/AbstractDelegateChangeSet.java | 5 ++ .../changeset/FaweStreamChangeSet.java | 48 +++++++++++++++---- .../core/util/MainUtil.java | 2 +- .../com/sk89q/worldedit/LocalSession.java | 2 +- .../worldedit/command/HistorySubCommands.java | 4 +- .../history/changeset/ChangeSet.java | 13 +++++ 9 files changed, 97 insertions(+), 29 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CopyPastaBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CopyPastaBrush.java index b635c1e7d..1b60124cb 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CopyPastaBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CopyPastaBrush.java @@ -91,7 +91,7 @@ public class CopyPastaBrush implements Brush, ResettableTool { newClipboard.setOrigin(position); ClipboardHolder holder = new ClipboardHolder(newClipboard); session.setClipboard(holder); - int blocks = builder.size(); + long blocks = builder.longSize(); player.print(Caption.of("fawe.worldedit.copy.command.copy", blocks)); } else { AffineTransform transform = null; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java index f8207f2dc..e40683f2e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java @@ -64,26 +64,47 @@ public class RollbackDatabase extends AsyncNotifyQueue { public Future init() { return call(() -> { try (PreparedStatement stmt = connection.prepareStatement("CREATE TABLE IF NOT EXISTS`" + this.prefix + - "edits` (`player` BLOB(16) NOT NULL,`id` INT NOT NULL, `time` INT NOT NULL,`x1`" + - "INT NOT NULL,`x2` INT NOT NULL,`z1` INT NOT NULL,`z2` INT NOT NULL,`y1`" + - "INT NOT NULL, `y2` INT NOT NULL, `size` INT NOT NULL, `command` VARCHAR, PRIMARY KEY (player, id))")) { + "_edits` (`player` BLOB(16) NOT NULL,`id` INT NOT NULL, `time` INT NOT NULL,`x1` " + + "INT NOT NULL,`x2` INT NOT NULL,`z1` INT NOT NULL,`z2` INT NOT NULL,`y1` " + + "INT NOT NULL, `y2` INT NOT NULL, `size` BIGINT NOT NULL, `command` VARCHAR, PRIMARY KEY (player, id))")) { stmt.executeUpdate(); } - try (PreparedStatement stmt = connection.prepareStatement("ALTER TABLE`" + this.prefix + "edits` ADD COLUMN `command` VARCHAR")) { + String alterTablePrefix = "ALTER TABLE`" + this.prefix + "edits` "; + try (PreparedStatement stmt = + connection.prepareStatement(alterTablePrefix + "ADD COLUMN `command` VARCHAR")) { stmt.executeUpdate(); } catch (SQLException ignored) { } // Already updated - try (PreparedStatement stmt = connection.prepareStatement("ALTER TABLE`" + this.prefix + "edits` ADD SIZE INT DEFAULT 0 NOT NULL")) { + try (PreparedStatement stmt = + connection.prepareStatement(alterTablePrefix + "ADD COLUMN `size` BIGINT DEFAULT 0 NOT NULL")) { stmt.executeUpdate(); } catch (SQLException ignored) { } // Already updated + + boolean migrated = false; + try (PreparedStatement stmt = + connection.prepareStatement("INSERT INTO `" + this.prefix + "_edits` " + + "(player, id, time, x1, x2, z1, z2, y1, y2, size, command) " + + "SELECT player, id, time, x1, x2, z1, z2, y1, y2, size, command " + + "FROM `" + this.prefix + "edits`")) { + + stmt.executeUpdate(); + migrated = true; + } catch (SQLException ignored) { + } // Already updated + if (migrated) { + try (PreparedStatement stmt = connection.prepareStatement("DROP TABLE `" + this.prefix + "edits`")) { + stmt.executeUpdate(); + } + } return true; }); } public Future delete(UUID uuid, int id) { return call(() -> { - try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + "edits` WHERE `player`=? AND `id`=?")) { + try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + "_edits` WHERE `player`=? " + + "AND `id`=?")) { stmt.setBytes(1, toBytes(uuid)); stmt.setInt(2, id); return stmt.executeUpdate(); @@ -94,7 +115,7 @@ public class RollbackDatabase extends AsyncNotifyQueue { public Future getEdit(@Nonnull UUID uuid, int id) { return call(() -> { try (PreparedStatement stmt = connection.prepareStatement("SELECT * FROM`" + this.prefix + - "edits` WHERE `player`=? AND `id`=?")) { + "_edits` WHERE `player`=? AND `id`=?")) { stmt.setBytes(1, toBytes(uuid)); stmt.setInt(2, id); ResultSet result = stmt.executeQuery(); @@ -119,7 +140,7 @@ public class RollbackDatabase extends AsyncNotifyQueue { CuboidRegion region = new CuboidRegion(BlockVector3.at(x1, y1, z1), BlockVector3.at(x2, y2, z2)); long time = result.getInt("time") * 1000L; - long size = result.getInt("size"); + long size = result.getLong("size"); String command = result.getString("command"); @@ -135,7 +156,7 @@ public class RollbackDatabase extends AsyncNotifyQueue { long now = System.currentTimeMillis() / 1000; final int then = (int) (now - diff); return call(() -> { - try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + "edits` WHERE `time` ? AND `x2` >= ? AND `x1` <= ? @@ -202,7 +223,8 @@ public class RollbackDatabase extends AsyncNotifyQueue { } if (delete && uuid != null) { try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + - "edits` WHERE `player`=? AND `time`>? AND `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? AND `z1`<=?")) { + "_edits` WHERE `player`=? AND `time`>? AND `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? " + + "AND `z1`<=?")) { byte[] uuidBytes = ByteBuffer .allocate(16) .putLong(uuid.getMostSignificantBits()) @@ -249,7 +271,7 @@ public class RollbackDatabase extends AsyncNotifyQueue { RollbackOptimizedHistory[] copy = IntStream.range(0, size) .mapToObj(i -> historyChanges.poll()).toArray(RollbackOptimizedHistory[]::new); - try (PreparedStatement stmt = connection.prepareStatement("INSERT OR REPLACE INTO`" + this.prefix + "edits`" + + try (PreparedStatement stmt = connection.prepareStatement("INSERT OR REPLACE INTO`" + this.prefix + "_edits`" + " (`player`,`id`,`time`,`x1`,`x2`,`z1`,`z2`,`y1`,`y2`,`command`,`size`) VALUES(?,?,?,?,?,?,?,?,?,?,?)")) { // `player`,`id`,`time`,`x1`,`x2`,`z1`,`z2`,`y1`,`y2`,`command`,`size`) VALUES(?,?,?,?,?,?,?,?,?,?,?)" for (RollbackOptimizedHistory change : copy) { @@ -270,7 +292,7 @@ public class RollbackDatabase extends AsyncNotifyQueue { stmt.setInt(8, pos1.y() - 128); stmt.setInt(9, pos2.y() - 128); stmt.setString(10, change.getCommand()); - stmt.setInt(11, change.size()); + stmt.setLong(11, change.longSize()); stmt.executeUpdate(); stmt.clearParameters(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java index 08165577f..346543a0b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java @@ -306,7 +306,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { } public boolean isEmpty() { - return queue.isEmpty() && workerSemaphore.availablePermits() == 1 && size() == 0; + return queue.isEmpty() && workerSemaphore.availablePermits() == 1 && longSize() == 0; } public void add(BlockVector3 loc, BaseBlock from, BaseBlock to) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractDelegateChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractDelegateChangeSet.java index 195a5fdbd..a44e73013 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractDelegateChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractDelegateChangeSet.java @@ -176,6 +176,11 @@ public class AbstractDelegateChangeSet extends AbstractChangeSet { return parent.size(); } + @Override + public long longSize() { + return parent.longSize(); + } + @Override public void delete() { parent.delete(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java index ad7c82c9f..e7132bf5a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java @@ -25,6 +25,7 @@ import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.NoSuchElementException; @@ -35,11 +36,18 @@ import java.util.NoSuchElementException; public abstract class FaweStreamChangeSet extends AbstractChangeSet { public static final int HEADER_SIZE = 9; - private static final int version = 1; + private static final int VERSION = 2; + // equivalent to Short#MIN_VALUE three times stored with [(x) & 0xff, ((rx) >> 8) & 0xff] + private static final byte[] MAGIC_NEW_RELATIVE = new byte[]{0, (byte) 128, 0, (byte) 128, 0, (byte) 128}; private int mode; private final int compression; private final int minY; + protected long blockSize; + private int originX; + private int originZ; + private int version; + protected FaweStreamIdDelegate idDel; protected FaweStreamPositionDelegate posDel; @@ -192,6 +200,20 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { int rx = -lx + (lx = x); int ry = -ly + (ly = y); int rz = -lz + (lz = z); + // Use LE/GE to ensure we don't accidentally write MAGIC_NEW_RELATIVE + if (rx >= Short.MAX_VALUE || rz >= Short.MAX_VALUE || rx <= Short.MIN_VALUE || rz <= Short.MIN_VALUE) { + stream.write(MAGIC_NEW_RELATIVE); + stream.write((byte) (x >> 24)); + stream.write((byte) (x >> 16)); + stream.write((byte) (x >> 8)); + stream.write((byte) (x)); + stream.write((byte) (z >> 24)); + stream.write((byte) (z >> 16)); + stream.write((byte) (z >> 8)); + stream.write((byte) (z)); + rx = 0; + rz = 0; + } stream.write((rx) & 0xff); stream.write(((rx) >> 8) & 0xff); stream.write((rz) & 0xff); @@ -203,6 +225,12 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { @Override public int readX(FaweInputStream is) throws IOException { is.readFully(buffer); + // Don't break reading version 1 history (just in case) + if (version == 2 && Arrays.equals(buffer, MAGIC_NEW_RELATIVE)) { + lx = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + is.read()); + lz = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + is.read()); + is.readFully(buffer); + } return lx = lx + ((buffer[0] & 0xFF) | (buffer[1] << 8)); } @@ -222,7 +250,7 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { public void writeHeader(OutputStream os, int x, int y, int z) throws IOException { os.write(mode); // Allows for version detection of history in case of changes to format. - os.write(version); + os.write(VERSION); setOrigin(x, z); os.write((byte) (x >> 24)); os.write((byte) (x >> 16)); @@ -238,8 +266,8 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { public void readHeader(InputStream is) throws IOException { // skip mode int mode = is.read(); - int version = is.read(); - if (version != FaweStreamChangeSet.version) { + version = is.read(); + if (version != 1 && version != VERSION) { // version 1 is fine throw new UnsupportedOperationException(String.format("Version %s history not supported!", version)); } // origin @@ -266,12 +294,17 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { } @Override - public int size() { + public long longSize() { // Flush so we can accurately get the size flush(); return blockSize; } + @Override + public int size() { + return (int) longSize(); + } + public abstract int getCompressedSize(); public abstract long getSizeInMemory(); @@ -304,11 +337,6 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { public abstract NBTInputStream getTileRemoveIS() throws IOException; - protected int blockSize; - - private int originX; - private int originZ; - public void setOrigin(int x, int z) { originX = x; originZ = z; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java index 6b693162e..83f951c13 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java @@ -217,7 +217,7 @@ public class MainUtil { // } else if (changeSet instanceof CPUOptimizedChangeSet) { // return changeSet.size() + 32; } else if (changeSet != null) { - return changeSet.size() * 128L; + return changeSet.longSize() * 128; // Approx } else { return 0; } 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 aa5f51e57..3dd5f5638 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -500,7 +500,7 @@ public class LocalSession implements TextureHolder { if (Settings.settings().HISTORY.USE_DISK) { LocalSession.MAX_HISTORY_SIZE = Integer.MAX_VALUE; } - if (changeSet.size() == 0) { + if (changeSet.longSize() == 0) { return; } loadSessionHistoryFromDisk(player.getUniqueId(), world); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java index 8d28ad1eb..38fc18415 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java @@ -251,7 +251,7 @@ public class HistorySubCommands { long seconds = (System.currentTimeMillis() - edit.getBDFile().lastModified()) / 1000; String timeStr = MainUtil.secToTime(seconds); - int size = edit.size(); + long size = edit.longSize(); boolean biomes = edit.getBioFile().exists(); boolean createdEnts = edit.getEnttFile().exists(); boolean removedEnts = edit.getEntfFile().exists(); @@ -335,7 +335,7 @@ public class HistorySubCommands { long seconds = (System.currentTimeMillis() - rollback.getBDFile().lastModified()) / 1000; String timeStr = MainUtil.secToTime(seconds); - int size = edit.size(); + long size = edit.longSize(); TranslatableComponent elem = Caption.of( "fawe.worldedit.history.find.element", diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java index b4ab9adc1..890b247d6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java @@ -81,11 +81,24 @@ public interface ChangeSet extends Closeable { * Get the number of stored changes. * * @return the change count + * @deprecated History could be larger than int max value so FAWE prefers {@link ChangeSet#longSize()} */ + @Deprecated(since = "TODO") int size(); //FAWE start + /** + * Get the number of stored changes. + * History could be larger than int max value so FAWE prefers this method. + * + * @return the change count + * @since TODO + */ + default long longSize() { + return size(); + } + /** * Close the changeset. */ From 0301fb01243ef2bd57da98a0e562721fc3c0f4e9 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sun, 28 Jul 2024 18:36:04 +0100 Subject: [PATCH 338/466] Revert "feat: improve fawe limits (#2773)" This reverts commit 6052fc3128410ec5dc9c2703b497082b8647d22c. --- .../fastasyncworldedit/core/FaweCache.java | 11 +- .../platform/binding/EditSessionHolder.java | 7 - .../platform/binding/ProvideBindings.java | 34 +-- .../core/extent/LimitExtent.java | 208 ++++++++---------- .../extent/filter/block/CharFilterBlock.java | 5 +- .../core/function/mask/ABlockMask.java | 2 +- .../core/function/mask/DataMask.java | 4 +- .../core/function/mask/IdMask.java | 4 +- .../function/mask/SingleBlockStateMask.java | 2 +- .../core/function/mask/SplatterBrushMask.java | 2 +- .../core/limit/ConcurrentFaweLimit.java | 201 ----------------- .../core/limit/FaweLimit.java | 65 ++---- .../core/limit/ProcessorFaweLimit.java | 135 ------------ .../core/queue/IBatchProcessor.java | 2 +- .../java/com/sk89q/worldedit/EditSession.java | 11 +- .../sk89q/worldedit/EditSessionBuilder.java | 16 +- .../com/sk89q/worldedit/LocalSession.java | 17 +- .../worldedit/command/BiomeCommands.java | 2 - .../worldedit/command/BrushCommands.java | 6 +- .../worldedit/command/ClipboardCommands.java | 3 - .../worldedit/command/GenerationCommands.java | 19 +- .../worldedit/command/HistoryCommands.java | 3 - .../worldedit/command/RegionCommands.java | 18 -- .../command/SnapshotUtilCommands.java | 2 - .../worldedit/command/UtilityCommands.java | 62 ++++-- .../worldedit/command/tool/AreaPickaxe.java | 2 +- .../command/tool/BlockDataCyler.java | 2 +- .../worldedit/command/tool/BlockReplacer.java | 2 +- .../worldedit/command/tool/BrushTool.java | 2 +- .../command/tool/FloatingTreeRemover.java | 2 +- .../worldedit/command/tool/FloodFillTool.java | 2 +- .../command/tool/LongRangeBuildTool.java | 4 +- .../command/tool/RecursivePickaxe.java | 2 +- .../worldedit/command/tool/SinglePickaxe.java | 2 +- .../worldedit/command/tool/StackTool.java | 2 +- .../worldedit/command/tool/TreePlanter.java | 2 +- .../worldedit/command/tool/brush/Brush.java | 11 - .../util/annotation/ConfirmHandler.java | 2 +- .../util/annotation/PreloadHandler.java | 2 +- .../SynchronousSettingExpected.java | 22 -- .../command/util/annotation/package-info.java | 1 - .../platform/PlatformCommandManager.java | 23 +- .../worldedit/function/mask/BiomeMask.java | 2 +- .../function/mask/BlockCategoryMask.java | 2 +- .../worldedit/function/mask/BlockMask.java | 2 +- .../function/mask/BlockStateMask.java | 2 +- .../function/mask/BlockTypeMask.java | 2 +- .../function/mask/ExistingBlockMask.java | 2 +- .../mask/InverseSingleBlockStateMask.java | 2 +- .../src/main/resources/lang/strings.json | 2 - 50 files changed, 236 insertions(+), 706 deletions(-) delete mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/EditSessionHolder.java delete mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/ConcurrentFaweLimit.java delete mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/ProcessorFaweLimit.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/SynchronousSettingExpected.java diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java index 3ed494298..526570296 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java @@ -192,22 +192,17 @@ public enum FaweCache implements Trimable { Type.OUTSIDE_REGION ); public static final FaweException MAX_CHECKS = new FaweException( - Caption.of("fawe.cancel.reason.max.checks"), - Type.MAX_CHECKS, - true - ); - public static final FaweException MAX_FAILS = new FaweException( - Caption.of("fawe.cancel.reason.max.fails"), + Caption.of("fawe.cancel.reason.max" + ".checks"), Type.MAX_CHECKS, true ); public static final FaweException MAX_CHANGES = new FaweException( - Caption.of("fawe.cancel.reason.max.changes"), + Caption.of("fawe.cancel.reason.max" + ".changes"), Type.MAX_CHANGES, false ); public static final FaweException LOW_MEMORY = new FaweException( - Caption.of("fawe.cancel.reason.low.memory"), + Caption.of("fawe.cancel.reason.low" + ".memory"), Type.LOW_MEMORY, false ); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/EditSessionHolder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/EditSessionHolder.java deleted file mode 100644 index 1fd588ec4..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/EditSessionHolder.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.fastasyncworldedit.core.extension.platform.binding; - -import com.sk89q.worldedit.EditSession; - -public record EditSessionHolder(EditSession session) { - -} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java index 3e38b1724..bc1e2bfbf 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java @@ -3,11 +3,7 @@ package com.fastasyncworldedit.core.extension.platform.binding; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.database.DBHandler; import com.fastasyncworldedit.core.database.RollbackDatabase; -import com.fastasyncworldedit.core.extent.LimitExtent; -import com.fastasyncworldedit.core.extent.processor.ExtentBatchProcessorHolder; -import com.fastasyncworldedit.core.internal.exception.FaweException; import com.fastasyncworldedit.core.regions.FaweMaskManager; -import com.fastasyncworldedit.core.util.ExtentTraverser; import com.fastasyncworldedit.core.util.TextureUtil; import com.fastasyncworldedit.core.util.image.ImageUtil; import com.sk89q.worldedit.EditSession; @@ -15,7 +11,6 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.command.util.annotation.AllowedRegion; -import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.platform.Actor; @@ -30,7 +25,6 @@ import org.enginehub.piston.inject.Key; import org.enginehub.piston.util.ValueProvider; import java.awt.image.BufferedImage; -import java.lang.reflect.Method; import java.net.URI; import java.util.Optional; @@ -58,33 +52,11 @@ public class ProvideBindings extends Bindings { @Binding public EditSession editSession(LocalSession localSession, Actor actor, InjectedValueAccess context) { - Method commandMethod = - context.injectedValue(Key.of(InjectedValueStore.class)).get().injectedValue(Key.of(Method.class)).get(); - Arguments arguments = context.injectedValue(Key.of(Arguments.class)).orElse(null); String command = arguments == null ? null : arguments.get(); - boolean synchronousSetting = commandMethod.getAnnotation(SynchronousSettingExpected.class) != null; - EditSessionHolder holder = context.injectedValue(Key.of(EditSessionHolder.class)).orElse(null); - EditSession editSession = holder != null ? holder.session() : null; - if (editSession == null) { - editSession = localSession.createEditSession(actor, command, synchronousSetting); - editSession.enableStandardMode(); - } else { - LimitExtent limitExtent = new ExtentTraverser<>(editSession).findAndGet(LimitExtent.class); - if (limitExtent != null) { - limitExtent.setProcessing(!synchronousSetting); - if (!synchronousSetting) { - ExtentBatchProcessorHolder processorHolder = new ExtentTraverser<>(editSession).findAndGet( - ExtentBatchProcessorHolder.class); - if (processorHolder != null) { - processorHolder.addProcessor(limitExtent); - } else { - throw new FaweException(Caption.of("fawe.error.no-process-non-synchronous-edit")); - } - } - } - Request.request().setEditSession(editSession); - } + EditSession editSession = localSession.createEditSession(actor, command); + editSession.enableStandardMode(); + Request.request().setEditSession(editSession); return editSession; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java index 33f19bfaa..d02ff9320 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java @@ -1,17 +1,11 @@ package com.fastasyncworldedit.core.extent; import com.fastasyncworldedit.core.extent.filter.block.ExtentFilterBlock; -import com.fastasyncworldedit.core.extent.processor.ProcessorScope; +import com.fastasyncworldedit.core.function.generator.GenBase; +import com.fastasyncworldedit.core.function.generator.Resource; import com.fastasyncworldedit.core.internal.exception.FaweException; -import com.fastasyncworldedit.core.limit.ConcurrentFaweLimit; import com.fastasyncworldedit.core.limit.FaweLimit; -import com.fastasyncworldedit.core.limit.ProcessorFaweLimit; import com.fastasyncworldedit.core.queue.Filter; -import com.fastasyncworldedit.core.queue.IBatchProcessor; -import com.fastasyncworldedit.core.queue.IChunk; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.fastasyncworldedit.core.util.ExtentTraverser; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEditException; @@ -23,6 +17,7 @@ import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.formatting.text.Component; @@ -42,22 +37,18 @@ import java.util.Set; import java.util.UUID; import java.util.function.Consumer; -public class LimitExtent extends AbstractDelegateExtent implements IBatchProcessor { +public class LimitExtent extends AbstractDelegateExtent { private final FaweLimit limit; private final boolean[] faweExceptionReasonsUsed = new boolean[FaweException.Type.values().length]; private final Consumer onErrorMessage; - private final int chunk_size; - private boolean processing; /** * Create a new instance. * * @param extent the extent * @param limit the limit - * @deprecated Use {@link LimitExtent#LimitExtent(Extent, FaweLimit, Consumer, boolean, boolean)} */ - @Deprecated(forRemoval = true, since = "TODO") public LimitExtent(Extent extent, FaweLimit limit) { this(extent, limit, c -> { }); @@ -69,41 +60,11 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess * @param extent the extent * @param limit the limit * @param onErrorMessage consumer to handle a component generated by exceptions - * @deprecated Use {@link LimitExtent#LimitExtent(Extent, FaweLimit, Consumer, boolean, boolean)} */ - @Deprecated(forRemoval = true, since = "TODO") public LimitExtent(Extent extent, FaweLimit limit, Consumer onErrorMessage) { - this(extent, limit, onErrorMessage, false, false); - } - - /** - * Create a new instance. - * - * @param extent the extent - * @param limit the limit - * @param onErrorMessage consumer to handle a component generated by exceptions - * @param processing if this limit extent is expected to be processing - * @param expectSynchronousSetting if synchronous block setting is expected - * @since TODO - */ - public LimitExtent( - Extent extent, - FaweLimit limit, - Consumer onErrorMessage, - boolean processing, - boolean expectSynchronousSetting - ) { super(extent); - if (!expectSynchronousSetting) { - this.limit = new ConcurrentFaweLimit(limit); - } else if (processing) { - this.limit = new ProcessorFaweLimit(limit); - } else { - this.limit = limit; - } + this.limit = limit; this.onErrorMessage = onErrorMessage; - this.chunk_size = 16 * 16 * (extent.getMaxY() - extent.getMinY()); - this.processing = !expectSynchronousSetting; } private void handleException(FaweException e) { @@ -120,7 +81,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess public List getEntities(Region region) { limit.THROW_MAX_CHECKS(region.getVolume()); try { - return extent.getEntities(region); + return super.getEntities(region); } catch (FaweException e) { handleException(e); return Collections.emptyList(); @@ -131,7 +92,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess public List getEntities() { limit.THROW_MAX_CHECKS(); try { - return extent.getEntities(); + return super.getEntities(); } catch (FaweException e) { handleException(e); return Collections.emptyList(); @@ -144,7 +105,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess limit.THROW_MAX_CHANGES(); limit.THROW_MAX_ENTITIES(); try { - return extent.createEntity(location, entity); + return super.createEntity(location, entity); } catch (FaweException e) { handleException(e); return null; @@ -157,7 +118,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess limit.THROW_MAX_CHANGES(); limit.THROW_MAX_ENTITIES(); try { - return extent.createEntity(location, entity, uuid); + return super.createEntity(location, entity, uuid); } catch (FaweException e) { handleException(e); return null; @@ -169,7 +130,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess limit.THROW_MAX_CHANGES(); limit.THROW_MAX_ENTITIES(); try { - extent.removeEntity(x, y, z, uuid); + super.removeEntity(x, y, z, uuid); } catch (FaweException e) { handleException(e); } @@ -177,9 +138,9 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess @Override public boolean regenerateChunk(int x, int z, @Nullable BiomeType type, @Nullable Long seed) { - limit.THROW_MAX_CHANGES(chunk_size); + limit.THROW_MAX_CHANGES(Character.MAX_VALUE); try { - return extent.regenerateChunk(x, z, type, seed); + return super.regenerateChunk(x, z, type, seed); } catch (FaweException e) { handleException(e); return false; @@ -190,7 +151,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess public int getHighestTerrainBlock(int x, int z, int minY, int maxY) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return extent.getHighestTerrainBlock(x, z, minY, maxY); + return super.getHighestTerrainBlock(x, z, minY, maxY); } catch (FaweException e) { handleException(e); return minY; @@ -201,7 +162,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return extent.getHighestTerrainBlock(x, z, minY, maxY, filter); + return super.getHighestTerrainBlock(x, z, minY, maxY, filter); } catch (FaweException e) { handleException(e); return minY; @@ -212,7 +173,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return extent.getNearestSurfaceLayer(x, z, y, minY, maxY); + return super.getNearestSurfaceLayer(x, z, y, minY, maxY); } catch (FaweException e) { handleException(e); return minY; @@ -223,7 +184,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir); + return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir); } catch (FaweException e) { handleException(e); return minY; @@ -234,7 +195,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY); + return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY); } catch (FaweException e) { handleException(e); return minY; @@ -245,7 +206,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax); + return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax); } catch (FaweException e) { handleException(e); return minY; @@ -256,7 +217,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask); + return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask); } catch (FaweException e) { handleException(e); return minY; @@ -276,47 +237,91 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess ) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir); + return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir); } catch (FaweException e) { handleException(e); return minY; } } + @Override + public void addCaves(Region region) throws WorldEditException { + limit.THROW_MAX_CHECKS(region.getVolume()); + limit.THROW_MAX_CHANGES(region.getVolume()); + super.addCaves(region); + } + + @Override + public void generate(Region region, GenBase gen) throws WorldEditException { + limit.THROW_MAX_CHECKS(region.getVolume()); + limit.THROW_MAX_CHANGES(region.getVolume()); + super.generate(region, gen); + } + + @Override + public void addSchems(Region region, Mask mask, List clipboards, int rarity, boolean rotate) throws + WorldEditException { + limit.THROW_MAX_CHECKS(region.getVolume()); + limit.THROW_MAX_CHANGES(region.getVolume()); + super.addSchems(region, mask, clipboards, rarity, rotate); + } + + @Override + public void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException { + limit.THROW_MAX_CHECKS(region.getVolume()); + limit.THROW_MAX_CHANGES(region.getVolume()); + super.spawnResource(region, gen, rarity, frequency); + } + + @Override + public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws + WorldEditException { + limit.THROW_MAX_CHECKS(region.getVolume()); + limit.THROW_MAX_CHANGES(region.getVolume()); + super.addOre(region, mask, material, size, frequency, rarity, minY, maxY); + } + + @Override + public void addOres(Region region, Mask mask) throws WorldEditException { + limit.THROW_MAX_CHECKS(region.getVolume()); + limit.THROW_MAX_CHANGES(region.getVolume()); + super.addOres(region, mask); + } + @Override public List> getBlockDistribution(Region region) { limit.THROW_MAX_CHECKS(region.getVolume()); - return extent.getBlockDistribution(region); + return super.getBlockDistribution(region); } @Override public List> getBlockDistributionWithData(Region region) { limit.THROW_MAX_CHECKS(region.getVolume()); - return extent.getBlockDistributionWithData(region); + return super.getBlockDistributionWithData(region); } @Override public int countBlocks(Region region, Set searchBlocks) { limit.THROW_MAX_CHECKS(region.getVolume()); - return extent.countBlocks(region, searchBlocks); + return super.countBlocks(region, searchBlocks); } @Override public int countBlocks(Region region, Mask searchMask) { limit.THROW_MAX_CHECKS(region.getVolume()); - return extent.countBlocks(region, searchMask); + return super.countBlocks(region, searchMask); } @Override public > int setBlocks(Region region, B block) throws MaxChangedBlocksException { limit.THROW_MAX_CHANGES(region.getVolume()); - return extent.setBlocks(region, block); + return super.setBlocks(region, block); } @Override public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException { limit.THROW_MAX_CHANGES(region.getVolume()); - return extent.setBlocks(region, pattern); + return super.setBlocks(region, pattern); } @Override @@ -324,34 +329,41 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess MaxChangedBlocksException { limit.THROW_MAX_CHECKS(region.getVolume()); limit.THROW_MAX_CHANGES(region.getVolume()); - return extent.replaceBlocks(region, filter, replacement); + return super.replaceBlocks(region, filter, replacement); } @Override public int replaceBlocks(Region region, Set filter, Pattern pattern) throws MaxChangedBlocksException { limit.THROW_MAX_CHECKS(region.getVolume()); limit.THROW_MAX_CHANGES(region.getVolume()); - return extent.replaceBlocks(region, filter, pattern); + return super.replaceBlocks(region, filter, pattern); } @Override public int replaceBlocks(Region region, Mask mask, Pattern pattern) throws MaxChangedBlocksException { limit.THROW_MAX_CHECKS(region.getVolume()); limit.THROW_MAX_CHANGES(region.getVolume()); - return extent.replaceBlocks(region, mask, pattern); + return super.replaceBlocks(region, mask, pattern); + } + + @Override + public int center(Region region, Pattern pattern) throws MaxChangedBlocksException { + limit.THROW_MAX_CHECKS(region.getVolume()); + limit.THROW_MAX_CHANGES(region.getVolume()); + return super.center(region, pattern); } @Override public int setBlocks(Set vset, Pattern pattern) { limit.THROW_MAX_CHANGES(vset.size()); - return extent.setBlocks(vset, pattern); + return super.setBlocks(vset, pattern); } @Override public T apply(Region region, T filter, boolean full) { limit.THROW_MAX_CHECKS(region.getVolume()); limit.THROW_MAX_CHANGES(region.getVolume()); - return extent.apply(region, filter, full); + return super.apply(region, filter, full); } @Override @@ -381,14 +393,14 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess } limit.THROW_MAX_CHECKS(size); limit.THROW_MAX_CHANGES(size); - return extent.apply(positions, filter); + return super.apply(positions, filter); } @Override public BlockState getBlock(BlockVector3 position) { limit.THROW_MAX_CHECKS(); try { - return extent.getBlock(position); + return super.getBlock(position); } catch (FaweException e) { handleException(e); return BlockTypes.AIR.getDefaultState(); @@ -399,7 +411,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess public BlockState getBlock(int x, int y, int z) { limit.THROW_MAX_CHECKS(); try { - return extent.getBlock(x, y, z); + return super.getBlock(x, y, z); } catch (FaweException e) { handleException(e); return BlockTypes.AIR.getDefaultState(); @@ -410,7 +422,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess public BaseBlock getFullBlock(BlockVector3 position) { limit.THROW_MAX_CHECKS(); try { - return extent.getFullBlock(position); + return super.getFullBlock(position); } catch (FaweException e) { handleException(e); return BlockTypes.AIR.getDefaultState().toBaseBlock(); @@ -421,7 +433,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess public BaseBlock getFullBlock(int x, int y, int z) { limit.THROW_MAX_CHECKS(); try { - return extent.getFullBlock(x, y, z); + return super.getFullBlock(x, y, z); } catch (FaweException e) { handleException(e); return BlockTypes.AIR.getDefaultState().toBaseBlock(); @@ -432,7 +444,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess public BiomeType getBiome(BlockVector3 position) { limit.THROW_MAX_CHECKS(); try { - return extent.getBiome(position); + return super.getBiome(position); } catch (FaweException e) { handleException(e); return BiomeTypes.FOREST; @@ -443,7 +455,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess public BiomeType getBiomeType(int x, int y, int z) { limit.THROW_MAX_CHECKS(); try { - return extent.getBiomeType(x, y, z); + return super.getBiomeType(x, y, z); } catch (FaweException e) { handleException(e); return BiomeTypes.FOREST; @@ -458,7 +470,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess limit.THROW_MAX_BLOCKSTATES(); } try { - return extent.setBlock(position, block); + return super.setBlock(position, block); } catch (FaweException e) { handleException(e); return false; @@ -472,7 +484,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess limit.THROW_MAX_BLOCKSTATES(); } try { - return extent.setBlock(x, y, z, block); + return super.setBlock(x, y, z, block); } catch (FaweException e) { handleException(e); return false; @@ -482,9 +494,9 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess @Override public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { limit.THROW_MAX_CHANGES(); - limit.THROW_MAX_BLOCKSTATES(); + limit.MAX_BLOCKSTATES(); try { - return extent.setTile(x, y, z, tile); + return super.setTile(x, y, z, tile); } catch (FaweException e) { handleException(e); return false; @@ -495,7 +507,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess public boolean setBiome(BlockVector3 position, BiomeType biome) { limit.THROW_MAX_CHANGES(); try { - return extent.setBiome(position, biome); + return super.setBiome(position, biome); } catch (FaweException e) { handleException(e); return false; @@ -506,41 +518,11 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess public boolean setBiome(int x, int y, int z, BiomeType biome) { limit.THROW_MAX_CHANGES(); try { - return extent.setBiome(x, y, z, biome); + return super.setBiome(x, y, z, biome); } catch (FaweException e) { handleException(e); return false; } } - public void setProcessing(boolean processing) { - this.processing = processing; - } - - @Override - public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { - if (!processing) { - return set; - } - int tiles = set.getTiles().size(); - int ents = set.getEntities().size() + set.getEntityRemoves().size(); - limit.THROW_MAX_CHANGES(tiles + ents); - limit.THROW_MAX_BLOCKSTATES(tiles); - limit.THROW_MAX_ENTITIES(ents); - return set; - } - - @Override - public Extent construct(final Extent child) { - if (extent != child) { - new ExtentTraverser(this).setNext(child); - } - return this; - } - - @Override - public ProcessorScope getScope() { - return ProcessorScope.READING_SET_BLOCKS; - } - } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java index f569ff0bb..579f04a9a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java @@ -170,13 +170,10 @@ public class CharFilterBlock extends ChunkFilterBlock { @Override public synchronized final void filter(Filter filter) { - initSet(); for (y = 0, index = 0; y < 16; y++) { for (z = 0; z < 16; z++) { for (x = 0; x < 16; x++, index++) { - if (setArr[index] != BlockTypesCache.ReservedIDs.__RESERVED__) { - filter.applyBlock(this); - } + filter.applyBlock(this); } } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ABlockMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ABlockMask.java index ed5b028dd..7fdebdded 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ABlockMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ABlockMask.java @@ -26,7 +26,7 @@ public abstract class ABlockMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - return test(vector.getBlock(getExtent())); + return test(getExtent().getBlock(vector)); } public abstract boolean test(BlockState state); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/DataMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/DataMask.java index 84b8f77ad..2b3ad7edb 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/DataMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/DataMask.java @@ -16,9 +16,9 @@ public class DataMask extends AbstractExtentMask implements ResettableMask { @Override public boolean test(BlockVector3 vector) { if (data != -1) { - return vector.getBlock(getExtent()).getInternalPropertiesId() == data; + return getExtent().getBlock(vector).getInternalPropertiesId() == data; } else { - data = vector.getBlock(getExtent()).getInternalPropertiesId(); + data = getExtent().getBlock(vector).getInternalPropertiesId(); return true; } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/IdMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/IdMask.java index b0ba4fb59..49c90183a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/IdMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/IdMask.java @@ -24,9 +24,7 @@ public class IdMask extends AbstractExtentMask implements ResettableMask { @Override public boolean test(BlockVector3 vector) { - int blockID = vector.getBlock(getExtent()).getInternalBlockTypeId(); - int testId = id.compareAndExchange(-1, blockID); - return blockID == testId || testId == -1; + return test(getExtent(), vector); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SingleBlockStateMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SingleBlockStateMask.java index 400f32163..32d853bda 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SingleBlockStateMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SingleBlockStateMask.java @@ -30,7 +30,7 @@ public class SingleBlockStateMask extends ABlockMask { @Override public boolean test(BlockVector3 vector) { - int test = vector.getBlock(getExtent()).getOrdinal(); + int test = getExtent().getBlock(vector).getOrdinal(); return ordinal == test || isAir && test == 0; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SplatterBrushMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SplatterBrushMask.java index d80399be4..250969616 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SplatterBrushMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SplatterBrushMask.java @@ -40,7 +40,7 @@ public class SplatterBrushMask extends AbstractExtentMask { double dist = vector.distanceSq(position); synchronized (placed) { if (dist < size2 && !placed.contains(vector) && ThreadLocalRandom.current().nextInt(5) < 2 && surface.test(vector)) { - placed.add(vector.toImmutable()); + placed.add(vector); return true; } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/ConcurrentFaweLimit.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/ConcurrentFaweLimit.java deleted file mode 100644 index 91ec1621d..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/ConcurrentFaweLimit.java +++ /dev/null @@ -1,201 +0,0 @@ -package com.fastasyncworldedit.core.limit; - -import com.fastasyncworldedit.core.FaweCache; - -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -/** - * Allows concurrent limit calculations - * - * @since TODO - */ -public class ConcurrentFaweLimit extends FaweLimit { - - public AtomicLong ATOMIC_MAX_CHANGES = new AtomicLong(); - public AtomicInteger ATOMIC_MAX_FAILS = new AtomicInteger(); - public AtomicLong ATOMIC_MAX_CHECKS = new AtomicLong(); - public AtomicInteger ATOMIC_MAX_ITERATIONS = new AtomicInteger(); - public AtomicInteger ATOMIC_MAX_BLOCKSTATES = new AtomicInteger(); - public AtomicInteger ATOMIC_MAX_ENTITIES = new AtomicInteger(); - - public ConcurrentFaweLimit(FaweLimit other) { - set(other); - } - - @Override - public boolean MAX_CHANGES() { - return ATOMIC_MAX_CHANGES.decrementAndGet() < 0; - } - - @Override - public boolean MAX_FAILS() { - return ATOMIC_MAX_FAILS.decrementAndGet() < 0; - } - - @Override - public boolean MAX_CHECKS() { - return ATOMIC_MAX_CHECKS.decrementAndGet() < 0; - } - - @Override - public boolean MAX_ITERATIONS() { - return ATOMIC_MAX_ITERATIONS.decrementAndGet() < 0; - } - - @Override - public boolean MAX_BLOCKSTATES() { - return ATOMIC_MAX_BLOCKSTATES.decrementAndGet() < 0; - } - - @Override - public boolean MAX_ENTITIES() { - return ATOMIC_MAX_ENTITIES.decrementAndGet() < 0; - } - - @Override - public void THROW_MAX_CHANGES() { - if (ATOMIC_MAX_CHANGES.decrementAndGet() < 0) { - throw FaweCache.MAX_CHANGES; - } - } - - @Override - public void THROW_MAX_FAILS() { - if (ATOMIC_MAX_FAILS.decrementAndGet() < 0) { - throw FaweCache.MAX_FAILS; - } - } - - @Override - public void THROW_MAX_CHECKS() { - if (ATOMIC_MAX_CHECKS.decrementAndGet() < 0) { - throw FaweCache.MAX_CHECKS; - } - } - - @Override - public void THROW_MAX_ITERATIONS() { - if (ATOMIC_MAX_ITERATIONS.decrementAndGet() < 0) { - throw FaweCache.MAX_ITERATIONS; - } - } - - @Override - public void THROW_MAX_BLOCKSTATES() { - if (ATOMIC_MAX_BLOCKSTATES.decrementAndGet() < 0) { - throw FaweCache.MAX_TILES; - } - } - - @Override - public void THROW_MAX_ENTITIES() { - if (ATOMIC_MAX_ENTITIES.decrementAndGet() < 0) { - throw FaweCache.MAX_ENTITIES; - } - } - - @Override - public void THROW_MAX_CHANGES(int amt) { - if (amt == 0) { - return; - } - if (ATOMIC_MAX_CHANGES.addAndGet(-amt) < 0) { - throw FaweCache.MAX_CHANGES; - } - } - - @Override - public void THROW_MAX_CHANGES(long amt) { - if (amt == 0) { - return; - } - if (ATOMIC_MAX_CHANGES.addAndGet(-amt) < 0) { - throw FaweCache.MAX_CHANGES; - } - } - - @Override - public void THROW_MAX_FAILS(int amt) { - if (amt == 0) { - return; - } - if (ATOMIC_MAX_FAILS.addAndGet(-amt) < 0) { - throw FaweCache.MAX_FAILS; - } - } - - @Override - public void THROW_MAX_CHECKS(int amt) { - if (amt == 0) { - return; - } - if (ATOMIC_MAX_CHECKS.addAndGet(-amt) < 0) { - throw FaweCache.MAX_CHECKS; - } - } - - @Override - public void THROW_MAX_CHECKS(long amt) { - if (amt == 0) { - return; - } - if (ATOMIC_MAX_CHECKS.addAndGet(-amt) < 0) { - throw FaweCache.MAX_CHECKS; - } - } - - @Override - public void THROW_MAX_ITERATIONS(int amt) { - if (amt == 0) { - return; - } - if (ATOMIC_MAX_ITERATIONS.addAndGet(-amt) < 0) { - throw FaweCache.MAX_ITERATIONS; - } - } - - @Override - public void THROW_MAX_BLOCKSTATES(int amt) { - if (amt == 0) { - return; - } - if (ATOMIC_MAX_BLOCKSTATES.addAndGet(-amt) < 0) { - throw FaweCache.MAX_TILES; - } - } - - @Override - public void THROW_MAX_ENTITIES(int amt) { - if (amt == 0) { - return; - } - if (ATOMIC_MAX_ENTITIES.addAndGet(-amt) < 0) { - throw FaweCache.MAX_ENTITIES; - } - } - - @Override - public void set(FaweLimit other) { - super.set(other); - ATOMIC_MAX_CHANGES.set(other.MAX_CHANGES); - ATOMIC_MAX_FAILS.set(other.MAX_FAILS); - ATOMIC_MAX_CHECKS.set(other.MAX_CHECKS); - ATOMIC_MAX_ITERATIONS.set(other.MAX_ITERATIONS); - ATOMIC_MAX_BLOCKSTATES.set(other.MAX_BLOCKSTATES); - ATOMIC_MAX_ENTITIES.set(other.MAX_ENTITIES); - } - - @Override - public FaweLimit getLimitUsed(FaweLimit originalLimit) { - FaweLimit newLimit = new FaweLimit(); - newLimit.MAX_CHANGES = originalLimit.MAX_CHANGES - this.ATOMIC_MAX_CHANGES.get(); - newLimit.MAX_FAILS = originalLimit.MAX_FAILS - this.ATOMIC_MAX_FAILS.get(); - newLimit.MAX_CHECKS = originalLimit.MAX_CHECKS - this.ATOMIC_MAX_CHECKS.get(); - newLimit.MAX_ITERATIONS = originalLimit.MAX_ITERATIONS - this.ATOMIC_MAX_ITERATIONS.get(); - newLimit.MAX_BLOCKSTATES = originalLimit.MAX_BLOCKSTATES - this.ATOMIC_MAX_BLOCKSTATES.get(); - newLimit.MAX_ENTITIES = originalLimit.MAX_ENTITIES - this.ATOMIC_MAX_ENTITIES.get(); - return newLimit; - } - -} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java index f7a99dd35..d17787f03 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java @@ -1,7 +1,6 @@ package com.fastasyncworldedit.core.limit; import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.internal.exception.FaweException; import com.fastasyncworldedit.core.configuration.Settings; import java.util.Collections; @@ -10,12 +9,12 @@ import java.util.Set; public class FaweLimit { public int MAX_ACTIONS = 0; - public volatile long MAX_CHANGES = 0; - public volatile int MAX_FAILS = 0; - public volatile long MAX_CHECKS = 0; - public volatile int MAX_ITERATIONS = 0; - public volatile int MAX_BLOCKSTATES = 0; - public volatile int MAX_ENTITIES = 0; + public long MAX_CHANGES = 0; + public int MAX_FAILS = 0; + public long MAX_CHECKS = 0; + public int MAX_ITERATIONS = 0; + public int MAX_BLOCKSTATES = 0; + public int MAX_ENTITIES = 0; public int MAX_HISTORY = 0; public int SCHEM_FILE_SIZE_LIMIT = 0; public int SCHEM_FILE_NUM_LIMIT = 0; @@ -162,85 +161,85 @@ public class FaweLimit { return MAX_ENTITIES-- > 0; } - public void THROW_MAX_CHANGES() throws FaweException { + public void THROW_MAX_CHANGES() { if (MAX_CHANGES-- <= 0) { throw FaweCache.MAX_CHANGES; } } - public void THROW_MAX_FAILS() throws FaweException { + public void THROW_MAX_FAILS() { if (MAX_FAILS-- <= 0) { - throw FaweCache.MAX_FAILS; + throw FaweCache.MAX_CHECKS; } } - public void THROW_MAX_CHECKS() throws FaweException { + public void THROW_MAX_CHECKS() { if (MAX_CHECKS-- <= 0) { throw FaweCache.MAX_CHECKS; } } - public void THROW_MAX_ITERATIONS() throws FaweException { + public void THROW_MAX_ITERATIONS() { if (MAX_ITERATIONS-- <= 0) { throw FaweCache.MAX_ITERATIONS; } } - public void THROW_MAX_BLOCKSTATES() throws FaweException { + public void THROW_MAX_BLOCKSTATES() { if (MAX_BLOCKSTATES-- <= 0) { throw FaweCache.MAX_TILES; } } - public void THROW_MAX_ENTITIES() throws FaweException { + public void THROW_MAX_ENTITIES() { if (MAX_ENTITIES-- <= 0) { throw FaweCache.MAX_ENTITIES; } } - public void THROW_MAX_CHANGES(int amt) throws FaweException { + public void THROW_MAX_CHANGES(int amt) { if ((MAX_CHANGES -= amt) <= 0) { throw FaweCache.MAX_CHANGES; } } - public void THROW_MAX_CHANGES(long amt) throws FaweException { + public void THROW_MAX_CHANGES(long amt) { if ((MAX_CHANGES -= amt) <= 0) { throw FaweCache.MAX_CHANGES; } } - public void THROW_MAX_FAILS(int amt) throws FaweException { + public void THROW_MAX_FAILS(int amt) { if ((MAX_FAILS -= amt) <= 0) { - throw FaweCache.MAX_FAILS; + throw FaweCache.MAX_CHECKS; } } - public void THROW_MAX_CHECKS(int amt) throws FaweException { + public void THROW_MAX_CHECKS(int amt) { if ((MAX_CHECKS -= amt) <= 0) { throw FaweCache.MAX_CHECKS; } } - public void THROW_MAX_CHECKS(long amt) throws FaweException { + public void THROW_MAX_CHECKS(long amt) { if ((MAX_CHECKS -= amt) <= 0) { throw FaweCache.MAX_CHECKS; } } - public void THROW_MAX_ITERATIONS(int amt) throws FaweException { + public void THROW_MAX_ITERATIONS(int amt) { if ((MAX_ITERATIONS -= amt) <= 0) { throw FaweCache.MAX_ITERATIONS; } } - public void THROW_MAX_BLOCKSTATES(int amt) throws FaweException { + public void THROW_MAX_BLOCKSTATES(int amt) { if ((MAX_BLOCKSTATES -= amt) <= 0) { throw FaweCache.MAX_TILES; } } - public void THROW_MAX_ENTITIES(int amt) throws FaweException { + public void THROW_MAX_ENTITIES(int amt) { if ((MAX_ENTITIES -= amt) <= 0) { throw FaweCache.MAX_ENTITIES; } @@ -271,22 +270,6 @@ public class FaweLimit { && MAX_BUTCHER_RADIUS == Integer.MAX_VALUE; } - /** - * Get an {@link FaweLimit} representing the amount of a limit used from a given "original" limit - * - * @since TODO - */ - public FaweLimit getLimitUsed(FaweLimit originalLimit) { - FaweLimit newLimit = new FaweLimit(); - newLimit.MAX_CHANGES = originalLimit.MAX_CHANGES - this.MAX_CHANGES; - newLimit.MAX_FAILS = originalLimit.MAX_FAILS - this.MAX_FAILS; - newLimit.MAX_CHECKS = originalLimit.MAX_CHECKS - this.MAX_CHECKS; - newLimit.MAX_ITERATIONS = originalLimit.MAX_ITERATIONS - this.MAX_ITERATIONS; - newLimit.MAX_BLOCKSTATES = originalLimit.MAX_BLOCKSTATES - this.MAX_BLOCKSTATES; - newLimit.MAX_ENTITIES = originalLimit.MAX_ENTITIES - this.MAX_ENTITIES; - return newLimit; - } - public void set(FaweLimit limit) { MAX_ACTIONS = limit.MAX_ACTIONS; MAX_CHANGES = limit.MAX_CHANGES; @@ -348,8 +331,4 @@ public class FaweLimit { return MAX_CHANGES + ""; } - public ProcessorFaweLimit toConcurrent() { - return new ProcessorFaweLimit(this); - } - } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/ProcessorFaweLimit.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/ProcessorFaweLimit.java deleted file mode 100644 index 47c97a78b..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/ProcessorFaweLimit.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.fastasyncworldedit.core.limit; - -import com.fastasyncworldedit.core.FaweCache; - -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -/** - * Allows concurrent limit calculations for THROW_MAX_XXX(amount) methods. Other methods use the default implementations in - * {@link FaweLimit} - * - * @since TODO - */ -public class ProcessorFaweLimit extends FaweLimit { - - public AtomicLong ATOMIC_MAX_CHANGES = new AtomicLong(); - public AtomicInteger ATOMIC_MAX_FAILS = new AtomicInteger(); - public AtomicLong ATOMIC_MAX_CHECKS = new AtomicLong(); - public AtomicInteger ATOMIC_MAX_ITERATIONS = new AtomicInteger(); - public AtomicInteger ATOMIC_MAX_BLOCKSTATES = new AtomicInteger(); - public AtomicInteger ATOMIC_MAX_ENTITIES = new AtomicInteger(); - - public ProcessorFaweLimit(FaweLimit other) { - set(other); - } - - @Override - public void THROW_MAX_CHANGES(int amt) { - if (amt == 0) { - return; - } - final long changes = MAX_CHANGES; - if (ATOMIC_MAX_CHANGES.updateAndGet(i -> (MAX_CHANGES = Math.min(i, changes) - amt)) < 0) { - throw FaweCache.MAX_CHANGES; - } - } - - @Override - public void THROW_MAX_CHANGES(long amt) { - if (amt == 0) { - return; - } - final long changes = MAX_CHANGES; - if (ATOMIC_MAX_CHANGES.updateAndGet(i -> (MAX_CHANGES = Math.min(i, changes) - amt))< 0) { - throw FaweCache.MAX_CHANGES; - } - } - - @Override - public void THROW_MAX_FAILS(int amt) { - if (amt == 0) { - return; - } - final int fails = MAX_FAILS; - if (ATOMIC_MAX_FAILS.updateAndGet(i -> (MAX_FAILS = Math.min(i, fails) - amt)) < 0) { - throw FaweCache.MAX_FAILS; - } - } - - @Override - public void THROW_MAX_CHECKS(int amt) { - final long checks = MAX_CHECKS; - if (ATOMIC_MAX_CHECKS.updateAndGet(i -> (MAX_CHECKS = Math.min(i, checks) - amt)) < 0) { - throw FaweCache.MAX_CHECKS; - } - } - - @Override - public void THROW_MAX_CHECKS(long amt) { - if (amt == 0) { - return; - } - final long checks = MAX_CHECKS; - if (ATOMIC_MAX_CHECKS.updateAndGet(i -> (MAX_CHECKS = Math.min(i, checks) - amt)) < 0) { - throw FaweCache.MAX_CHECKS; - } - } - - @Override - public void THROW_MAX_ITERATIONS(int amt) { - if (amt == 0) { - return; - } - final int iterations = MAX_ITERATIONS; - if (ATOMIC_MAX_ITERATIONS.updateAndGet(i -> (MAX_ITERATIONS = Math.min(i, iterations) - amt)) < 0) { - throw FaweCache.MAX_ITERATIONS; - } - } - - @Override - public void THROW_MAX_BLOCKSTATES(int amt) { - if (amt == 0) { - return; - } - final int states = MAX_BLOCKSTATES; - if (ATOMIC_MAX_BLOCKSTATES.updateAndGet(i -> (MAX_BLOCKSTATES = Math.min(i, states) - amt)) < 0) { - throw FaweCache.MAX_TILES; - } - } - - @Override - public void THROW_MAX_ENTITIES(int amt) { - if (amt == 0) { - return; - } - final int entities = MAX_ENTITIES; - if (ATOMIC_MAX_ENTITIES.updateAndGet(i -> (MAX_ENTITIES = Math.min(i, entities) - amt)) < 0) { - throw FaweCache.MAX_ENTITIES; - } - } - - @Override - public void set(FaweLimit other) { - super.set(other); - ATOMIC_MAX_CHANGES.set(other.MAX_CHANGES); - ATOMIC_MAX_FAILS.set(other.MAX_FAILS); - ATOMIC_MAX_CHECKS.set(other.MAX_CHECKS); - ATOMIC_MAX_ITERATIONS.set(other.MAX_ITERATIONS); - ATOMIC_MAX_BLOCKSTATES.set(other.MAX_BLOCKSTATES); - ATOMIC_MAX_ENTITIES.set(other.MAX_ENTITIES); - } - - @Override - public FaweLimit getLimitUsed(FaweLimit originalLimit) { - FaweLimit newLimit = new FaweLimit(); - newLimit.MAX_CHANGES = originalLimit.MAX_CHANGES - Math.min(this.ATOMIC_MAX_CHANGES.get(), MAX_CHANGES); - newLimit.MAX_FAILS = originalLimit.MAX_FAILS - Math.min(this.ATOMIC_MAX_FAILS.get(), MAX_FAILS); - newLimit.MAX_CHECKS = originalLimit.MAX_CHECKS - Math.min(this.ATOMIC_MAX_CHECKS.get(), MAX_CHECKS); - newLimit.MAX_ITERATIONS = originalLimit.MAX_ITERATIONS - Math.min(this.ATOMIC_MAX_ITERATIONS.get(), MAX_ITERATIONS); - newLimit.MAX_BLOCKSTATES = originalLimit.MAX_BLOCKSTATES - Math.min(this.ATOMIC_MAX_BLOCKSTATES.get(), MAX_BLOCKSTATES); - newLimit.MAX_ENTITIES = originalLimit.MAX_ENTITIES - Math.min(this.ATOMIC_MAX_ENTITIES.get(), MAX_ENTITIES); - return newLimit; - } - -} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java index 6a5473979..4ba91a4f3 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java @@ -50,7 +50,7 @@ public interface IBatchProcessor { } /** - * Convert this processor into an Extent based processor instead of a queue batch based one. + * Convert this processor into an Extent based processor instead of a queue batch based on. */ @Nullable Extent construct(Extent child); 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 7bc243134..926265bfb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -308,7 +308,16 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { * @return Limit remaining */ public FaweLimit getLimitUsed() { - return originalLimit.getLimitUsed(limit); + FaweLimit newLimit = new FaweLimit(); + newLimit.MAX_ACTIONS = originalLimit.MAX_ACTIONS - limit.MAX_ACTIONS; + newLimit.MAX_CHANGES = originalLimit.MAX_CHANGES - limit.MAX_CHANGES; + newLimit.MAX_FAILS = originalLimit.MAX_FAILS - limit.MAX_FAILS; + newLimit.MAX_CHECKS = originalLimit.MAX_CHECKS - limit.MAX_CHECKS; + newLimit.MAX_ITERATIONS = originalLimit.MAX_ITERATIONS - limit.MAX_ITERATIONS; + newLimit.MAX_BLOCKSTATES = originalLimit.MAX_BLOCKSTATES - limit.MAX_BLOCKSTATES; + newLimit.MAX_ENTITIES = originalLimit.MAX_ENTITIES - limit.MAX_ENTITIES; + newLimit.MAX_HISTORY = limit.MAX_HISTORY; + return newLimit; } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java index 5cf0cf745..ca6f3b6a5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java @@ -104,7 +104,6 @@ public final class EditSessionBuilder { private Extent extent; private boolean compiled; private boolean wrapped; - private boolean expectSynchronousSetting = false; private @Nullable World world; @@ -416,15 +415,6 @@ public final class EditSessionBuilder { return setDirty(); } - public EditSessionBuilder expectSynchronousSetting(boolean expectSynchronousSetting) { - this.expectSynchronousSetting = expectSynchronousSetting; - return setDirty(); - } - - public boolean isExpectingSynchronousSetting() { - return this.expectSynchronousSetting; - } - /** * Compile the builder to the settings given. Prepares history, limits, lighting, etc. */ @@ -645,11 +635,7 @@ public final class EditSessionBuilder { }; } if (limit != null && !limit.isUnlimited()) { - this.extent = new LimitExtent(this.extent, limit, onErrorMessage, placeChunks && combineStages, expectSynchronousSetting); - // Only process if we're not necessarily going to catch tiles via Extent#setBlock, e.g. because using PQE methods - if (placeChunks && combineStages && !expectSynchronousSetting) { - queue.addProcessor((LimitExtent) this.extent); - } + this.extent = new LimitExtent(this.extent, limit, onErrorMessage); } this.extent = wrapExtent(this.extent, eventBus, event, EditSession.Stage.BEFORE_HISTORY); } 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 3dd5f5638..d82bcd463 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -1725,25 +1725,10 @@ public class LocalSession implements TextureHolder { * @return an edit session */ public EditSession createEditSession(Actor actor) { - //FAWE start return createEditSession(actor, null); } public EditSession createEditSession(Actor actor, String command) { - return createEditSession(actor, command, false); - } - - /** - * Construct a new edit session. - * - * @param actor the actor - * @param command the command executed resulting in the creation of the edit session - * @param expectSynchronousSetting if it is expected that blocks will only be set synchronously, i.e. from one thread (at a - * time) - * @return an edit session - * @since TODO - */ - public EditSession createEditSession(Actor actor, String command, boolean expectSynchronousSetting) { checkNotNull(actor); World world = null; @@ -1754,6 +1739,7 @@ public class LocalSession implements TextureHolder { } // Create an edit session + //FAWE start - we don't use the edit session builder yet EditSession editSession; EditSessionBuilder builder = WorldEdit.getInstance().newEditSessionBuilder().world(world); if (actor.isPlayer() && actor instanceof Player) { @@ -1763,7 +1749,6 @@ public class LocalSession implements TextureHolder { } builder.command(command); builder.fastMode(!this.sideEffectSet.doesApplyAny()); - builder.expectSynchronousSetting(expectSynchronousSetting); editSession = builder.build(); 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 1f551aefa..a60968da1 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 @@ -30,7 +30,6 @@ import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.command.util.annotation.Confirm; import com.sk89q.worldedit.command.util.annotation.Preload; -import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; @@ -180,7 +179,6 @@ public class BiomeCommands { ) @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) - @SynchronousSettingExpected // TODO improve using filter/chunk-based-placement @Confirm(Confirm.Processor.REGION) @CommandPermissions("worldedit.biome.set") public void setBiome( 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 8f1733fbb..664e656c4 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 @@ -992,15 +992,15 @@ public class BrushCommands { Expression radius, @Arg(desc = "Command to run") List input, - @Switch(name = 'h', desc = "Hide any printed output") - boolean hide + @Switch(name = 'p', desc = "Show any printed output") + boolean print ) throws WorldEditException { worldEdit.checkMaxBrushRadius( radius, context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) ); String cmd = StringMan.join(input, " "); - set(context, new CommandBrush(cmd, !hide), "worldedit.brush.command").setSize(radius); + set(context, new CommandBrush(cmd, print), "worldedit.brush.command").setSize(radius); } @Command( 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 a8fa5076e..378449755 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 @@ -47,7 +47,6 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.annotation.Confirm; import com.sk89q.worldedit.command.util.annotation.Preload; -import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; @@ -439,7 +438,6 @@ public class ClipboardCommands { desc = "Place the clipboard's contents without applying transformations (e.g. rotate)" ) @CommandPermissions("worldedit.clipboard.place") - @SynchronousSettingExpected @Logging(PLACEMENT) public void place( Actor actor, World world, LocalSession session, final EditSession editSession, @@ -504,7 +502,6 @@ public class ClipboardCommands { desc = "Paste the clipboard's contents" ) @CommandPermissions("worldedit.clipboard.paste") - @SynchronousSettingExpected @Logging(PLACEMENT) public void paste( Actor actor, World world, LocalSession session, EditSession editSession, 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 f2a3c80ed..4b2f98e0c 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 @@ -38,7 +38,6 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.annotation.Confirm; import com.sk89q.worldedit.command.util.annotation.Preload; -import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.mask.Mask; @@ -105,7 +104,6 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.cylinder") @Logging(PLACEMENT) - @SynchronousSettingExpected public int hcyl( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") @@ -154,7 +152,6 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.cylinder") @Logging(PLACEMENT) - @SynchronousSettingExpected public int cyl( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") @@ -200,7 +197,6 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.cone") @Logging(PLACEMENT) - @SynchronousSettingExpected public int cone(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") Pattern pattern, @@ -247,7 +243,6 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.sphere") @Logging(PLACEMENT) - @SynchronousSettingExpected public int hsphere( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") @@ -267,7 +262,6 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.sphere") @Logging(PLACEMENT) - @SynchronousSettingExpected public int sphere( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") @@ -319,7 +313,6 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.forest") @Logging(POSITION) - @SynchronousSettingExpected public int forestGen( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The size of the forest, in blocks", def = "10") @@ -344,7 +337,6 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.pumpkins") @Logging(POSITION) - @SynchronousSettingExpected public int pumpkins( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The size of the patch", def = "10") @@ -365,7 +357,6 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.pyramid") @Logging(PLACEMENT) - @SynchronousSettingExpected public int hollowPyramid( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to set") @@ -382,7 +373,6 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.pyramid") @Logging(PLACEMENT) - @SynchronousSettingExpected public int pyramid( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to set") @@ -410,7 +400,6 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.shape") @Logging(ALL) - @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int generate( Actor actor, LocalSession session, EditSession editSession, @@ -497,7 +486,6 @@ public class GenerationCommands { @CommandPermissions("worldedit.generation.shape.biome") @Logging(ALL) @Preload(Preload.PreloadCheck.PRELOAD) - @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int generateBiome( Actor actor, LocalSession session, EditSession editSession, @@ -576,7 +564,6 @@ public class GenerationCommands { @CommandPermissions("worldedit.generation.caves") @Logging(PLACEMENT) @Preload(Preload.PreloadCheck.PRELOAD) - @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public void caves( Actor actor, LocalSession session, EditSession editSession, @Selection Region region, @@ -615,7 +602,6 @@ public class GenerationCommands { @CommandPermissions("worldedit.generation.ore") @Logging(PLACEMENT) @Preload(Preload.PreloadCheck.PRELOAD) - @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public void ores( Actor actor, @@ -635,7 +621,6 @@ public class GenerationCommands { desc = "Generate an image" ) @CommandPermissions("worldedit.generation.image") - @SynchronousSettingExpected @Logging(PLACEMENT) public void image( Actor actor, @@ -700,7 +685,6 @@ public class GenerationCommands { @CommandPermissions("worldedit.generation.ore") @Logging(PLACEMENT) @Preload(Preload.PreloadCheck.PRELOAD) - @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public void ore( Actor actor, @@ -735,9 +719,8 @@ public class GenerationCommands { desc = "Creates a distorted sphere" ) @Logging(PLACEMENT) - @SynchronousSettingExpected @CommandPermissions("worldedit.generation.blob") - public int blob( + public int blobBrush( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "Pattern") Pattern pattern, 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 ba736e45e..d1a647587 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 @@ -27,7 +27,6 @@ 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.annotation.Confirm; -import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.inventory.BlockBag; @@ -62,7 +61,6 @@ public class HistoryCommands { desc = "Undoes the last action (from history)" ) @CommandPermissions({"worldedit.history.undo", "worldedit.history.undo.self"}) - @SynchronousSettingExpected public void undo( Actor actor, LocalSession session, @Confirm(Confirm.Processor.LIMIT) @Arg(desc = "Number of undoes to perform", def = "1") @@ -110,7 +108,6 @@ public class HistoryCommands { desc = "Redoes the last action (from history)" ) @CommandPermissions({"worldedit.history.redo", "worldedit.history.redo.self"}) - @SynchronousSettingExpected public void redo( Actor actor, LocalSession session, @Confirm(Confirm.Processor.LIMIT) @Arg(desc = "Number of redoes to perform", def = "1") 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 ac3490cca..6a121aa02 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 @@ -35,7 +35,6 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.annotation.Confirm; import com.sk89q.worldedit.command.util.annotation.Preload; -import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.GroundFunction; @@ -226,7 +225,6 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.line") @Logging(REGION) - @SynchronousSettingExpected public int line( Actor actor, EditSession editSession, @Selection Region region, @@ -259,7 +257,6 @@ public class RegionCommands { @CommandPermissions("worldedit.region.curve") @Logging(REGION) @Confirm(Confirm.Processor.REGION) - @SynchronousSettingExpected public int curve( Actor actor, EditSession editSession, @Selection Region region, @@ -318,7 +315,6 @@ public class RegionCommands { @CommandPermissions("worldedit.region.overlay") @Logging(REGION) @Confirm(Confirm.Processor.REGION) - @SynchronousSettingExpected // TODO improve using filter/chunk-based-placement public int overlay( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to overlay") @@ -337,7 +333,6 @@ public class RegionCommands { @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) @Confirm(Confirm.Processor.REGION) - @SynchronousSettingExpected // TODO improve using filter/chunk-based-placement public void lay( Actor actor, EditSession editSession, @@ -374,7 +369,6 @@ public class RegionCommands { ) @Logging(REGION) @CommandPermissions("worldedit.region.center") - @SynchronousSettingExpected public int center( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to set") @@ -392,8 +386,6 @@ public class RegionCommands { @CommandPermissions("worldedit.region.naturalize") @Logging(REGION) @Confirm(Confirm.Processor.REGION) - @SynchronousSettingExpected // TODO improve using filter/chunk-based-placement - @Preload(Preload.PreloadCheck.PRELOAD) public int naturalize(Actor actor, EditSession editSession, @Selection Region region) throws WorldEditException { int affected = editSession.naturalizeCuboidBlocks(region); actor.print(Caption.of("worldedit.naturalize.naturalized", TextComponent.of(affected))); @@ -445,7 +437,6 @@ public class RegionCommands { @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) @Confirm(Confirm.Processor.REGION) - @SynchronousSettingExpected public int smooth( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "# of iterations to perform", def = "1") @@ -519,7 +510,6 @@ public class RegionCommands { @CommandPermissions("worldedit.region.snowsmooth") @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) - @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int snowSmooth( Actor actor, EditSession editSession, @Selection Region region, @@ -546,7 +536,6 @@ public class RegionCommands { @CommandPermissions("worldedit.region.move") @Logging(ORIENTATION_REGION) @Preload(Preload.PreloadCheck.PRELOAD) - @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int move( Actor actor, World world, EditSession editSession, LocalSession session, @@ -610,7 +599,6 @@ public class RegionCommands { @CommandPermissions("worldedit.region.fall") @Logging(ORIENTATION_REGION) @Preload(Preload.PreloadCheck.PRELOAD) - @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public void fall( Actor actor, EditSession editSession, @@ -630,7 +618,6 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.stack") @Preload(Preload.PreloadCheck.PRELOAD) - @SynchronousSettingExpected @Logging(ORIENTATION_REGION) public int stack( Actor actor, World world, EditSession editSession, LocalSession session, @@ -696,7 +683,6 @@ public class RegionCommands { ) @CommandPermissions("worldedit.regen") @Logging(REGION) - @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) void regenerate( Actor actor, World world, LocalSession session, EditSession editSession, @@ -751,7 +737,6 @@ public class RegionCommands { @CommandPermissions("worldedit.region.deform") @Logging(ALL) @Preload(Preload.PreloadCheck.PRELOAD) - @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int deform( Actor actor, LocalSession session, EditSession editSession, @@ -829,7 +814,6 @@ public class RegionCommands { @CommandPermissions("worldedit.region.hollow") @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) - @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int hollow( Actor actor, EditSession editSession, @@ -864,7 +848,6 @@ public class RegionCommands { @CommandPermissions("worldedit.region.forest") @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) - @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int forest( Actor actor, EditSession editSession, @Selection Region region, @@ -886,7 +869,6 @@ public class RegionCommands { @CommandPermissions("worldedit.region.flora") @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) - @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int flora( Actor actor, EditSession editSession, @Selection Region region, 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 074711521..b98785631 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 @@ -28,7 +28,6 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; -import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.formatting.text.TextComponent; @@ -67,7 +66,6 @@ public class SnapshotUtilCommands { ) @Logging(REGION) @CommandPermissions("worldedit.snapshots.restore") - @SynchronousSettingExpected public void restore( Actor actor, World world, LocalSession session, EditSession editSession, @Arg(name = "snapshot", desc = "The snapshot to restore", def = "") 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 c7c6ab9a1..c81db21d8 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 @@ -44,7 +44,6 @@ import com.sk89q.worldedit.command.util.EntityRemover; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.PrintCommandHelp; import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; -import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; @@ -221,7 +220,6 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.fill") @Logging(PLACEMENT) - @SynchronousSettingExpected public int fill( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The blocks to fill with") @@ -313,7 +311,6 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.fill.recursive") @Logging(PLACEMENT) - @SynchronousSettingExpected public int fillr( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The blocks to fill with") @@ -346,7 +343,6 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.drain") @Logging(PLACEMENT) - @SynchronousSettingExpected public int drain( Actor actor, LocalSession session, EditSession editSession, //FAWE start - we take an expression over a double @@ -377,7 +373,6 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.fixlava") @Logging(PLACEMENT) - @SynchronousSettingExpected public int fixLava( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius to fix in") @@ -399,7 +394,6 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.fixwater") @Logging(PLACEMENT) - @SynchronousSettingExpected public int fixWater( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius to fix in") @@ -421,7 +415,6 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.removeabove") @Logging(PLACEMENT) - @SynchronousSettingExpected public int removeAbove( Actor actor, World world, LocalSession session, EditSession editSession, @Arg(desc = "The apothem of the square to remove from", def = "1") @@ -447,7 +440,6 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.removebelow") @Logging(PLACEMENT) - @SynchronousSettingExpected public int removeBelow( Actor actor, World world, LocalSession session, EditSession editSession, @Arg(desc = "The apothem of the square to remove from", def = "1") @@ -473,7 +465,6 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.removenear") @Logging(PLACEMENT) - @SynchronousSettingExpected public int removeNear( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The mask of blocks to remove") @@ -536,7 +527,6 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.snow") @Logging(PLACEMENT) - @SynchronousSettingExpected public int snow( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius of the cylinder to snow in", def = "10") @@ -576,7 +566,6 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.thaw") @Logging(PLACEMENT) - @SynchronousSettingExpected public int thaw( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius of the cylinder to thaw in", def = "10") @@ -606,7 +595,6 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.green") @Logging(PLACEMENT) - @SynchronousSettingExpected public int green( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius of the cylinder to convert in", def = "10") @@ -641,7 +629,6 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.extinguish") @Logging(PLACEMENT) - @SynchronousSettingExpected public int extinguish( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius of the square to remove in", def = "") @@ -856,6 +843,55 @@ public class UtilityCommands { } } +// @Command( +// name = "/hollowr", +// desc = "Hollow out a space recursively with a pattern" +// ) +// @CommandPermissions("worldedit.hollowr") +// @Logging(PLACEMENT) +// public int hollowr( +// Actor actor, +// LocalSession session, +// EditSession editSession, +// @Arg(desc = "The radius to hollow out") Expression radiusExp, +// @ArgFlag(name = 'p', desc = "The blocks to fill with") Pattern pattern, +// @ArgFlag(name = 'm', desc = "The blocks remove", def = "") Mask mask +// ) throws WorldEditException { +// //FAWE start +// double radius = radiusExp.evaluate(); +// //FAWE end +// radius = Math.max(1, radius); +// we.checkMaxRadius(radius); +// if (mask == null) { +// Mask mask = new MaskIntersection( +// new RegionMask(new EllipsoidRegion(null, origin, Vector3.at(radius, radius, radius))), +// new BoundedHeightMask( +// Math.max(lowerBound, minY), +// Math.min(maxY, origin.getBlockY()) +// ), +// Masks.negate(new ExistingBlockMask(this)) +// ); +// } +// +// // Want to replace blocks +// BlockReplace replace = new BlockReplace(this, pattern); +// +// // Pick how we're going to visit blocks +// RecursiveVisitor visitor; +// //FAWE start - provide extent for preloading, min/max y +// if (recursive) { +// visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), minY, maxY, this); +// } else { +// visitor = new DownwardVisitor(mask, replace, origin.getBlockY(), (int) (radius * 2 + 1), minY, maxY, this); +// } +// //FAWE end +// +// BlockVector3 pos = session.getPlacementPosition(actor); +// int affected = editSession.res(pos, pattern, radius, depth, true); +// actor.print(Caption.of("worldedit.fillr.created", TextComponent.of(affected))); +// return affected; +// } + public static List> filesToEntry(final File root, final List files, final UUID uuid) { return files.stream() .map(input -> { // Keep this functional, as transform is evaluated lazily 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 e1996520a..299908d99 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 @@ -64,7 +64,7 @@ public class AreaPickaxe implements BlockTool { return false; } - try (EditSession editSession = session.createEditSession(player, "AreaPickaxe", true)) { + try (EditSession editSession = session.createEditSession(player, "AreaPickaxe")) { editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop); int maxY = editSession.getMaxY(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java index 304fb9e77..2d35b2226 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java @@ -89,7 +89,7 @@ public class BlockDataCyler implements DoubleActionBlockTool { Property objProp = (Property) currentProperty; BaseBlock newBlock = block.with(objProp, currentProperty.getValues().get(index)); - try (EditSession editSession = session.createEditSession(player, null, true)) { + try (EditSession editSession = session.createEditSession(player)) { try { editSession.setBlock(blockPoint, newBlock); player.print(Caption.of( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java index 957ed3d83..75ef200c6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java @@ -63,7 +63,7 @@ public class BlockReplacer implements DoubleActionBlockTool { ) { BlockBag bag = session.getBlockBag(player); - try (EditSession editSession = session.createEditSession(player, null, true)) { + try (EditSession editSession = session.createEditSession(player)) { try { BlockVector3 position = clicked.toVector().toBlockPoint(); editSession.setBlock(position, pattern); 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 74b06b1f5..6021102a2 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 @@ -440,7 +440,7 @@ public class BrushTool Caption.of("fawe.error.no-perm", StringMan.join(current.getPermissions(), ","))); return false; } - try (EditSession editSession = session.createEditSession(player, current.toString(), brush.setsSynchronously())) { + try (EditSession editSession = session.createEditSession(player, current.toString())) { Location target = player.getBlockTrace(getRange(), true, traceMask); if (target == null) { 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 81d755b8c..385fcd2f3 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 @@ -86,7 +86,7 @@ public class FloatingTreeRemover implements BlockTool { return true; } - try (EditSession editSession = session.createEditSession(player, "FloatingTreeRemover", true)) { + try (EditSession editSession = session.createEditSession(player, "FloatingTreeRemover")) { try { final Set blockSet = bfs(world, clicked.toVector().toBlockPoint()); if (blockSet == null) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java index 6381e9356..3d8d63f7d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/FloodFillTool.java @@ -82,7 +82,7 @@ public class FloodFillTool implements BlockTool { return true; } - try (EditSession editSession = session.createEditSession(player, "FloodFillTool", true)) { + try (EditSession editSession = session.createEditSession(player, "FloodFillTool")) { try { //FAWE start - Respect masks Mask mask = initialType.toMask(editSession); 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 b1686ccd5..9e60fdcf3 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 @@ -61,7 +61,7 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo } BlockBag bag = session.getBlockBag(player); - try (EditSession editSession = session.createEditSession(player, "LongRangeBuildTool", true)) { + try (EditSession editSession = session.createEditSession(player, "LongRangeBuildTool")) { try { BlockVector3 blockPoint = pos.toVector().toBlockPoint(); BaseBlock applied = secondary.applyBlock(blockPoint); @@ -90,7 +90,7 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo } BlockBag bag = session.getBlockBag(player); - try (EditSession editSession = session.createEditSession(player, "LongRangeBuildTool", true)) { + try (EditSession editSession = session.createEditSession(player, "LongRangeBuildTool")) { try { BlockVector3 blockPoint = pos.toVector().toBlockPoint(); BaseBlock applied = primary.applyBlock(blockPoint); 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 a8b666ff6..9fad39f9d 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 @@ -79,7 +79,7 @@ public class RecursivePickaxe implements BlockTool { return false; } - try (EditSession editSession = session.createEditSession(player, "RecursivePickaxe", true)) { + try (EditSession editSession = session.createEditSession(player, "RecursivePickaxe")) { editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop); //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java index 152f7016a..b35865fb3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java @@ -62,7 +62,7 @@ public class SinglePickaxe implements BlockTool { return false; } - try (EditSession editSession = session.createEditSession(player, null, true)) { + try (EditSession editSession = session.createEditSession(player)) { try { editSession.getSurvivalExtent().setToolUse(config.superPickaxeDrop); editSession.setBlock(blockPoint, BlockTypes.AIR.getDefaultState()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/StackTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/StackTool.java index 8aa5761f5..614bbcf32 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/StackTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/StackTool.java @@ -59,7 +59,7 @@ public class StackTool implements BlockTool { } BlockBag bag = session.getBlockBag(player); - try (EditSession editSession = session.createEditSession(player, null, true)) { + try (EditSession editSession = session.createEditSession(player)) { BlockStateHolder block = editSession.getFullBlock(clicked.toVector().toBlockPoint()); try { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java index b2f6ae7cf..1f52ff103 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java @@ -60,7 +60,7 @@ public class TreePlanter implements BlockTool { @Nullable Direction face ) { - try (EditSession editSession = session.createEditSession(player, null, true)) { + try (EditSession editSession = session.createEditSession(player)) { try { boolean successful = false; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java index e38ae0d99..8efe2ab77 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java @@ -40,15 +40,4 @@ public interface Brush { */ void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException; - //FAWE start - /** - * If this brush is expected to set blocks synchronously, i.e. from one thread (at a time) - * - * @since TODO - */ - default boolean setsSynchronously() { - return true; - } - //FAWE end - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/ConfirmHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/ConfirmHandler.java index 5d6b66483..067f9cfeb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/ConfirmHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/ConfirmHandler.java @@ -12,7 +12,7 @@ import java.lang.reflect.Method; import java.util.Optional; /** - * Handles commands indicated as requiring confirmation. + * Logs called commands to a logger. */ public class ConfirmHandler implements CommandCallListener { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/PreloadHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/PreloadHandler.java index 037c94e5b..9e1dc106f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/PreloadHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/PreloadHandler.java @@ -11,7 +11,7 @@ import java.lang.reflect.Method; import java.util.Optional; /** - * Initialises preloading of chunks. + * Logs called commands to a logger. */ public class PreloadHandler implements CommandCallListener { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/SynchronousSettingExpected.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/SynchronousSettingExpected.java deleted file mode 100644 index 3cc936fda..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/SynchronousSettingExpected.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.sk89q.worldedit.command.util.annotation; - -import org.enginehub.piston.inject.InjectAnnotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Indicates it is expected that blocks will only be set synchronously, i.e. from one thread (at a time) - * - * @since TODO - */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ - ElementType.METHOD -}) -@InjectAnnotation -public @interface SynchronousSettingExpected { - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/package-info.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/package-info.java index f7f293277..006432a73 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/package-info.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/package-info.java @@ -8,7 +8,6 @@ * {@link com.sk89q.worldedit.command.util.annotation.PatternList}, * {@link com.sk89q.worldedit.command.util.annotation.Preload}, * {@link com.sk89q.worldedit.command.util.annotation.PreloadHandler}, - * {@link com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected}, * {@link com.sk89q.worldedit.command.util.annotation.Step}, * {@link com.sk89q.worldedit.command.util.annotation.Time} */ diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 65fc7c196..b03e4ce54 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -24,7 +24,6 @@ import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extension.platform.binding.Bindings; import com.fastasyncworldedit.core.extension.platform.binding.ConsumeBindings; -import com.fastasyncworldedit.core.extension.platform.binding.EditSessionHolder; import com.fastasyncworldedit.core.extension.platform.binding.PrimitiveBindings; import com.fastasyncworldedit.core.extension.platform.binding.ProvideBindings; import com.fastasyncworldedit.core.internal.command.MethodInjector; @@ -155,6 +154,7 @@ import org.enginehub.piston.inject.MemoizingValueAccess; import org.enginehub.piston.inject.MergedValueAccess; import org.enginehub.piston.part.SubCommandPart; import org.enginehub.piston.suggestion.Suggestion; +import org.enginehub.piston.util.HelpGenerator; import org.enginehub.piston.util.ValueProvider; import javax.annotation.Nonnull; @@ -227,6 +227,7 @@ public final class PlatformCommandManager { new ConfirmHandler(), new PreloadHandler() //FAWE end + )); // setup separate from main constructor // ensures that everything is definitely assigned @@ -311,6 +312,20 @@ public final class PlatformCommandManager { } ); //FAWE start + /* + globalInjectedValues.injectValue(Key.of(EditSession.class), + context -> { + LocalSession localSession = context.injectedValue(Key.of(LocalSession.class)) + .orElseThrow(() -> new IllegalStateException("No LocalSession")); + return context.injectedValue(Key.of(Actor.class)) + .map(actor -> { + EditSession editSession = localSession.createEditSession(actor); + editSession.enableStandardMode(); + Request.request().setEditSession(editSession); + return editSession; + }); + }); + */ // TODO: Ping @MattBDev to reimplement 2020-02-04 // globalInjectedValues.injectValue(Key.of(CFICommands.CFISettings.class), // context -> context.injectedValue(Key.of(Actor.class)) @@ -851,10 +866,10 @@ public final class PlatformCommandManager { store.injectValue(Key.of(InjectedValueStore.class), ValueProvider.constant(store)); store.injectValue(Key.of(Event.class), ValueProvider.constant(event)); //FAWE start - allow giving editsessions - if (event instanceof CommandEvent commandEvent) { - EditSession session = commandEvent.getSession(); + if (event instanceof CommandEvent) { + EditSession session = ((CommandEvent) event).getSession(); if (session != null) { - store.injectValue(Key.of(EditSessionHolder.class), context -> Optional.of(new EditSessionHolder(session))); + store.injectValue(Key.of(EditSession.class), context -> Optional.of(session)); } } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask.java index ab919b35f..cd3ef56d5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask.java @@ -94,7 +94,7 @@ public class BiomeMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - BiomeType biome = vector.getBiome(getExtent()); + BiomeType biome = getExtent().getBiome(vector); return biomes.contains(biome); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java index a1b869efb..bad9781ea 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java @@ -46,7 +46,7 @@ public class BlockCategoryMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - return category.contains(vector.getBlock(getExtent())); + return category.contains(getExtent().getBlock(vector)); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java index c7d3473f3..9f191a4cc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java @@ -204,7 +204,7 @@ public class BlockMask extends ABlockMask { @Override public boolean test(BlockVector3 vector) { - int test = vector.getBlock(getExtent()).getOrdinal(); + int test = getExtent().getBlock(vector).getOrdinal(); return ordinals[test] || replacesAir() && test == 0; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java index 0c563cdf7..ac558520c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java @@ -56,7 +56,7 @@ public class BlockStateMask extends AbstractExtentMask { //FAWE start @Override public boolean test(BlockVector3 vector) { - return test(vector.getBlock(getExtent())); + return test(getExtent().getBlock(vector)); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java index c3567b6d5..17f1419e5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java @@ -124,7 +124,7 @@ public class BlockTypeMask extends AbstractExtentMask { //FAWE start @Override public boolean test(BlockVector3 vector) { - return test(vector.getBlock(getExtent()).getBlockType()); + return test(getExtent().getBlock(vector).getBlockType()); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java index be62c2eae..b75a4cd1e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java @@ -41,7 +41,7 @@ public class ExistingBlockMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - return !vector.getBlock(getExtent()).getBlockType().getMaterial().isAir(); + return !getExtent().getBlock(vector).getBlockType().getMaterial().isAir(); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java index 6bb39b958..e8b14b95a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java @@ -29,7 +29,7 @@ public class InverseSingleBlockStateMask extends ABlockMask { @Override public boolean test(BlockVector3 vector) { - int test = vector.getBlock(getExtent()).getOrdinal(); + int test = getExtent().getBlock(vector).getOrdinal(); if (isAir && test == 0) { return false; } diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index fea3e7dd5..a56d98695 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -141,7 +141,6 @@ "fawe.error.limit.max-brush-radius": "Maximum brush radius in limit: {0}", "fawe.error.limit.max-radius": "Maximum radius in limit: {0}", "fawe.error.no-valid-on-hotbar": "No valid block types on hotbar", - "fawe.error.no-process-non-synchronous-edit": "No processor holder was found but edit is non-synchronous", "fawe.cancel.count": "Cancelled {0} edits.", "fawe.cancel.reason.confirm": "Use //confirm to execute {0}", "fawe.cancel.reason.confirm.region": "Your selection is large ({0} -> {1}, containing {3} blocks). Use //confirm to execute {2}", @@ -152,7 +151,6 @@ "fawe.cancel.reason.low.memory": "Low memory", "fawe.cancel.reason.max.changes": "Too many blocks changed", "fawe.cancel.reason.max.checks": "Too many block checks", - "fawe.cancel.reason.max.fails": "Too many fails", "fawe.cancel.reason.max.tiles": "Too many block entities", "fawe.cancel.reason.max.entities": "Too many entities", "fawe.cancel.reason.max.iterations": "Max iterations", From 638344d81573934733453c39cfebd38d63ee3fa6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 02:14:57 +0000 Subject: [PATCH 339/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.3.10 (#2860) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4f8f18a17..4e8b5252d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.3.9" +towny = "0.100.3.10" plotsquared = "7.3.8" # Third party From f93ad596c6723074c49ffc44ccdb210b0c811345 Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 31 Jul 2024 21:08:06 +0200 Subject: [PATCH 340/466] fix: correctly resolve file if extension is given (#2857) * fix: correctly resolve file if extension is given * Adjust error if ClipboardFormats#findByFile null --- .../java/com/fastasyncworldedit/core/util/MainUtil.java | 6 ++++++ .../java/com/sk89q/worldedit/command/SchematicCommands.java | 6 +++++- .../worldedit/extent/clipboard/io/ClipboardFormats.java | 1 - 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java index 83f951c13..0c323e47b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java @@ -712,6 +712,12 @@ public class MainUtil { return file; } } + if (filename.matches(".*\\.[\\w].*")) { + File file = MainUtil.resolveRelative(new File(dir, filename)); + if (file.exists()) { + return file; + } + } for (ClipboardFormat f : ClipboardFormats.getAll()) { File file = MainUtil.resolveRelative(new File(dir, filename + "." + f.getPrimaryFileExtension())); if (file.exists()) { 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 2d75b65b8..615702a19 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 @@ -401,7 +401,11 @@ public class SchematicCommands { if (format == null) { format = ClipboardFormats.findByFile(file); if (format == null) { - actor.print(Caption.of("worldedit.schematic.unknown-format", TextComponent.of(formatName))); + if (noExplicitFormat) { + actor.print(Caption.of("fawe.worldedit.schematic.schematic.load-failure", TextComponent.of(file.getName()))); + } else { + actor.print(Caption.of("worldedit.schematic.unknown-format", TextComponent.of(formatName))); + } return; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java index 786af54fa..801baa187 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java @@ -208,7 +208,6 @@ public class ClipboardFormats { } } return null; - } public static MultiClipboardHolder loadAllFromInput( From 069fd885661450582ac5c62487cbe93654a2abb9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 5 Aug 2024 01:11:19 +0000 Subject: [PATCH 341/466] Update antlr4 to v4.13.2 (#2868) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4e8b5252d..c46ddf207 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ auto-value = "1.11.0" findbugs = "3.0.2" rhino-runtime = "1.7.15" zstd-jni = "1.4.8-1" # Not latest as it can be difficult to obtain latest ZSTD libs -antlr4 = "4.13.1" +antlr4 = "4.13.2" json-simple = "1.1.1" jlibnoise = "1.0.0" jchronic = "0.2.4a" From 98c50cb719feddca2dbc4c476e1225fdb9ae353d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 5 Aug 2024 01:11:47 +0000 Subject: [PATCH 342/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.3.11 (#2869) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c46ddf207..69d0fc007 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.3.10" +towny = "0.100.3.11" plotsquared = "7.3.8" # Third party From 0c7104b45ba85b1402784489c640a4abb37b36ac Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 5 Aug 2024 04:02:00 +0000 Subject: [PATCH 343/466] Update gradle/actions action to v4 (#2871) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build-pr.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/upload-release-assets.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index e6ad24a7f..7b578480f 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -11,7 +11,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@v3 + uses: gradle/actions/wrapper-validation@v4 - name: Setup Java uses: actions/setup-java@v4 with: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5b44758dd..79aa448d8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@v3 + uses: gradle/actions/wrapper-validation@v4 - name: Setup Java uses: actions/setup-java@v4 with: diff --git a/.github/workflows/upload-release-assets.yml b/.github/workflows/upload-release-assets.yml index 22d6c6083..c6e0ea2cf 100644 --- a/.github/workflows/upload-release-assets.yml +++ b/.github/workflows/upload-release-assets.yml @@ -9,7 +9,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@v3 + uses: gradle/actions/wrapper-validation@v4 - name: Setup Java uses: actions/setup-java@v4 with: From 1a827fa8c1a26e8dae2f334b547e0a1c7a742b25 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 5 Aug 2024 04:02:17 +0000 Subject: [PATCH 344/466] Update dependency org.checkerframework:checker-qual to v3.46.0 (#2870) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 69d0fc007..89f03b0e1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.17.0" adventure-bukkit = "4.3.3" -checkerqual = "3.45.0" +checkerqual = "3.46.0" truezip = "6.8.4" auto-value = "1.11.0" findbugs = "3.0.2" From fcbd346d8f4a52b13857ff535c108762f86c1ab9 Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 7 Aug 2024 07:56:33 +0200 Subject: [PATCH 345/466] fix: do not StackOverflow when getting a section in FULL after awkward trim (#2863) --- .../implementation/blocks/CharBlocks.java | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java index 047394322..c338033f0 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java @@ -31,7 +31,9 @@ public abstract class CharBlocks implements IBlocks { char[] arr = blocks.blocks[layer]; if (arr == null) { // Chunk probably trimmed mid-operations, but do nothing about it to avoid other issues - return EMPTY.get(blocks, layer, false); + synchronized (blocks.sectionLocks[layer]) { + return getSkipFull(blocks, layer, aggressive); + } } return arr; } @@ -54,22 +56,7 @@ public abstract class CharBlocks implements IBlocks { if (blocks.sections[layer] == FULL) { return FULL.get(blocks, layer); } - char[] arr = blocks.blocks[layer]; - if (arr == null) { - arr = blocks.blocks[layer] = blocks.update(layer, null, aggressive); - if (arr == null) { - throw new IllegalStateException("Array cannot be null: " + blocks.getClass()); - } - } else { - blocks.blocks[layer] = blocks.update(layer, arr, aggressive); - if (blocks.blocks[layer] == null) { - throw new IllegalStateException("Array cannot be null (update): " + blocks.getClass()); - } - } - if (blocks.blocks[layer] != null) { - blocks.sections[layer] = FULL; - } - return arr; + return getSkipFull(blocks, layer, aggressive); } } @@ -262,6 +249,25 @@ public abstract class CharBlocks implements IBlocks { get(blocks, layer)[index] = value; } + static char[] getSkipFull(CharBlocks blocks, int layer, boolean aggressive) { + char[] arr = blocks.blocks[layer]; + if (arr == null) { + arr = blocks.blocks[layer] = blocks.update(layer, null, aggressive); + if (arr == null) { + throw new IllegalStateException("Array cannot be null: " + blocks.getClass()); + } + } else { + blocks.blocks[layer] = blocks.update(layer, arr, aggressive); + if (blocks.blocks[layer] == null) { + throw new IllegalStateException("Array cannot be null (update): " + blocks.getClass()); + } + } + if (blocks.blocks[layer] != null) { + blocks.sections[layer] = FULL; + } + return arr; + } + } } From 480a672477a3b2e144ee482585f601bcb1290c39 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 10 Aug 2024 19:40:34 +0000 Subject: [PATCH 346/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.3.12 (#2873) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 89f03b0e1..d16c6493d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.3.11" +towny = "0.100.3.12" plotsquared = "7.3.8" # Third party From 4578719f70bbe55268fafff8d8962d83613e18fc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 10 Aug 2024 19:44:39 +0000 Subject: [PATCH 347/466] Update dependency net.kyori:adventure-platform-bukkit to v4.3.4 (#2875) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d16c6493d..243c51c38 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -22,7 +22,7 @@ bstats = "3.0.2" sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.17.0" -adventure-bukkit = "4.3.3" +adventure-bukkit = "4.3.4" checkerqual = "3.46.0" truezip = "6.8.4" auto-value = "1.11.0" From 41d294e73b08920204a851278e18cd88dd3dbe83 Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Sun, 11 Aug 2024 21:23:45 +0200 Subject: [PATCH 348/466] Support 1.21.1 (#2877) * chore: add support for 1.21.1 * chore: remove old chunk system references in 1.21 adapter (paper) * chore: re-word exception message --- build.gradle.kts | 2 +- buildSrc/build.gradle.kts | 2 +- .../adapters/adapter-1_21/build.gradle.kts | 4 +- .../ext/fawe/v1_21_R1/PaperweightAdapter.java | 4 +- .../fawe/v1_21_R1/PaperweightFaweAdapter.java | 15 ++++--- .../v1_21_R1/PaperweightPlatformAdapter.java | 40 ++++--------------- 6 files changed, 20 insertions(+), 47 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 4dd632c1d..94f8120b9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -83,7 +83,7 @@ allprojects { } applyCommonConfiguration() -val supportedVersions = listOf("1.19.4", "1.20", "1.20.4", "1.20.5", "1.20.6", "1.21") +val supportedVersions = listOf("1.19.4", "1.20", "1.20.4", "1.20.5", "1.20.6", "1.21", "1.21.1") tasks { supportedVersions.forEach { diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index f116fd23e..1ad464f55 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -24,7 +24,7 @@ dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2") implementation("com.github.johnrengelman:shadow:8.1.1") - implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.1") + implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.2") constraints { val asmVersion = "[9.7,)" implementation("org.ow2.asm:asm:$asmVersion") { diff --git a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts index 39ff980f6..5067b921a 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts @@ -11,7 +11,7 @@ repositories { } dependencies { - // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21-R0.1-20240629.091304-42") + // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/ + the().paperDevBundle("1.21.1-R0.1-20240810.223713-4") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java index f66bb1460..b958c8ba7 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java @@ -195,8 +195,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter getEntities(LevelChunk chunk) { - ExceptionCollector collector = new ExceptionCollector<>(); if (PaperLib.isPaper()) { - if (POST_CHUNK_REWRITE) { - try { - //noinspection unchecked - return (List) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level.moonrise$getEntityLookup().getChunk(chunk.locX, chunk.locZ)); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=true]", e); - } - } try { - EntityList entityList = (EntityList) LEVEL_CHUNK_ENTITIES.get(chunk); - return List.of(entityList.getRawData()); - } catch (IllegalAccessException e) { - collector.add(new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=false]", e)); - // fall through + //noinspection unchecked + return (List) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level + .moonrise$getEntityLookup() + .getChunk(chunk.locX, chunk.locZ)); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException("Failed to lookup entities [PAPER=true]", e); } } try { //noinspection unchecked return ((PersistentEntitySectionManager) (SERVER_LEVEL_ENTITY_MANAGER.get(chunk.level))).getEntities(chunk.getPos()); } catch (IllegalAccessException e) { - collector.add(new RuntimeException("Failed to lookup entities [PAPER=false]", e)); + throw new RuntimeException("Failed to lookup entities [PAPER=false]", e); } - collector.throwIfPresent(); - return List.of(); } record FakeIdMapBlock(int size) implements IdMap { From b5c22d6275fede3a4fa1f92d3a74ac2bebc3e2dd Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 11 Aug 2024 21:37:10 +0200 Subject: [PATCH 349/466] Release 2.11.1 Signed-off-by: Alexander Brandes --- build.gradle.kts | 2 +- .../src/main/java/com/fastasyncworldedit/core/FaweAPI.java | 2 +- .../core/extent/clipboard/io/FastSchematicReaderV3.java | 2 +- .../core/extent/clipboard/io/FastSchematicWriterV3.java | 2 +- .../fastasyncworldedit/core/function/generator/SchemGen.java | 4 ++-- .../sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java | 2 +- .../sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java | 2 +- .../java/com/sk89q/worldedit/history/changeset/ChangeSet.java | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 94f8120b9..b0216b3bf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s-%s", rootVersion, buildNumber) +version = String.format("%s", rootVersion) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java index 0bf621bc6..28367a949 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java @@ -119,7 +119,7 @@ public class FaweAPI { * @deprecated Opens streams that are not then closed. Use {@link ClipboardFormats#findByFile(File)} and its relevant * methods to allow closing created streams/closing the reader (which will close the stream(s)) */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.1") public static Clipboard load(File file) throws IOException { return ClipboardFormats.findByFile(file).load(file); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java index db98d2203..8b6aa6cc8 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java @@ -66,7 +66,7 @@ import java.util.zip.GZIPInputStream; * Not necessarily much faster than {@link com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Reader}, but uses a * stream based approach to keep the memory overhead minimal (especially in larger schematics) * - * @since TODO + * @since 2.11.1 */ @SuppressWarnings("removal") // JNBT public class FastSchematicReaderV3 implements ClipboardReader { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriterV3.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriterV3.java index e00839eb0..1d1f0df2a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriterV3.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriterV3.java @@ -36,7 +36,7 @@ import java.util.function.Function; * Faster, stream-based implementation of {@link com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Writer} for * writing schematics conforming the sponge schematic v3 format. * - * @since TODO + * @since 2.11.1 */ @SuppressWarnings("removal") // Yes, JNBT is deprecated - we know public class FastSchematicWriterV3 implements ClipboardWriter { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/SchemGen.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/SchemGen.java index 83207f50b..775e9cf4c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/SchemGen.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/SchemGen.java @@ -27,7 +27,7 @@ public class SchemGen implements Resource { /** * @deprecated Use {@link SchemGen#SchemGen(Mask, Extent, List, boolean, Region)} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.1") public SchemGen(Mask mask, Extent extent, List clipboards, boolean randomRotate) { this.mask = mask; this.extent = extent; @@ -39,7 +39,7 @@ public class SchemGen implements Resource { /** * New instance. Places a schematic on terrain at a given x,z when appropriate * - * @since TODO + * @since 2.11.1 */ public SchemGen(Mask mask, Extent extent, List clipboards, boolean randomRotate, Region region) { this.mask = mask; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java index cb1b97e2a..1961dd8cb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java @@ -101,7 +101,7 @@ public interface ClipboardFormat { * * @param inputStream The stream * @return true if the given stream is of this format - * @since TODO + * @since 2.11.1 */ default boolean isFormat(InputStream inputStream) { return false; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java index 801baa187..d1529c803 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java @@ -177,7 +177,7 @@ public class ClipboardFormats { * @deprecated DO NOT USE. Sponge formats 2 and 3 both use .schem by default. */ @Nullable - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.1") public static ClipboardFormat findByExtension(String extension) { checkNotNull(extension); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java index 890b247d6..750324569 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java @@ -83,7 +83,7 @@ public interface ChangeSet extends Closeable { * @return the change count * @deprecated History could be larger than int max value so FAWE prefers {@link ChangeSet#longSize()} */ - @Deprecated(since = "TODO") + @Deprecated(since = "2.11.1") int size(); //FAWE start @@ -93,7 +93,7 @@ public interface ChangeSet extends Closeable { * History could be larger than int max value so FAWE prefers this method. * * @return the change count - * @since TODO + * @since 2.11.1 */ default long longSize() { return size(); From a779be4b260fb52b61b3417f0c5e5594569a0bce Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 11 Aug 2024 21:45:41 +0200 Subject: [PATCH 350/466] Back to snapshot for development Signed-off-by: Alexander Brandes --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index b0216b3bf..12ad4a353 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.11.1") +var rootVersion by extra("2.11.2") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s", rootVersion) +version = String.format("%s-%s", rootVersion, buildNumber) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From 5b3291d7c23f3cefc896ce47f24cbafbd70596c8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2024 02:27:12 +0000 Subject: [PATCH 351/466] Update dependency paperweight-userdev to v1.21.1-R0.1-20240811.223934-9 (#2879) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts index 5067b921a..253af67e6 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.1-R0.1-20240810.223713-4") + the().paperDevBundle("1.21.1-R0.1-20240811.223934-9") compileOnly(libs.paperlib) } From d1e2511603dcdbec6865f76cba0bb595b24d6e0e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2024 02:27:29 +0000 Subject: [PATCH 352/466] Update plotsquared to v7.3.9 (#2880) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 243c51c38..12f0abf24 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" towny = "0.100.3.12" -plotsquared = "7.3.8" +plotsquared = "7.3.9" # Third party bstats = "3.0.2" From acbe2f476a8e908092effc59828c3550392735ef Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 00:48:19 +0000 Subject: [PATCH 353/466] Update dependency paperweight-userdev to v1.21.1-R0.1-20240818.224341-32 (#2885) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts index 253af67e6..a589c6b09 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.1-R0.1-20240811.223934-9") + the().paperDevBundle("1.21.1-R0.1-20240818.224341-32") compileOnly(libs.paperlib) } From 543f3c4229e21d0a7a56be6a2f23d6a39f88d6ee Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 00:48:37 +0000 Subject: [PATCH 354/466] Update plugin xyz.jpenilla.run-paper to v2.3.1 (#2886) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 12ad4a353..5c8ce8016 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,7 +7,7 @@ import xyz.jpenilla.runpaper.task.RunServer plugins { id("io.github.gradle-nexus.publish-plugin") version "2.0.0" - id("xyz.jpenilla.run-paper") version "2.3.0" + id("xyz.jpenilla.run-paper") version "2.3.1" } if (!File("$rootDir/.git").exists()) { From 886264e0d97ef01b32f6d6ac74363e3c20d27b70 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 03:54:59 +0000 Subject: [PATCH 355/466] Update dependency commons-cli:commons-cli to v1.9.0 (#2887) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 12f0abf24..927abab42 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -35,7 +35,7 @@ jlibnoise = "1.0.0" jchronic = "0.2.4a" lz4-java = "1.8.0" lz4-stream = "1.0.0" -commons-cli = "1.8.0" +commons-cli = "1.9.0" paperlib = "1.0.8" paster = "1.1.6" vault = "1.7.1" From a64e09a7b0aca2e32a496b3c500f568dce4ae0dc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 03:59:38 +0000 Subject: [PATCH 356/466] Update dependency gradle to v8.10 (#2888) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 09523c0e5..9355b4155 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 1a674723e9cd9c8607b437b7b3c48397f1f07291 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Thu, 22 Aug 2024 18:31:28 +0200 Subject: [PATCH 357/466] Update wrapper Signed-off-by: Alexander Brandes --- gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 43504 bytes gradlew | 7 +++++-- gradlew.bat | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f3d4ba8a0da8d277868979cfbc8ad796..2c3521197d7c4586c843d1d3e9090525f1898cde 100644 GIT binary patch delta 8703 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 Ojj7^59?Sdh$^Qpp*~F>< delta 8662 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 diff --git a/gradlew b/gradlew index 1aa94a426..f5feea6d6 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 7101f8e46..9b42019c7 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## From 2b1326ec7fac8c8fdc02642bcc60ba6ca348495e Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 25 Aug 2024 11:43:56 +0200 Subject: [PATCH 358/466] Update Shadow Signed-off-by: Alexander Brandes --- buildSrc/build.gradle.kts | 2 +- buildSrc/src/main/kotlin/LibsConfig.kt | 2 +- buildSrc/src/main/kotlin/PlatformConfig.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 1ad464f55..7b227e2d8 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -23,7 +23,7 @@ val properties = Properties().also { props -> dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2") - implementation("com.github.johnrengelman:shadow:8.1.1") + implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.0") implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.2") constraints { val asmVersion = "[9.7,)" diff --git a/buildSrc/src/main/kotlin/LibsConfig.kt b/buildSrc/src/main/kotlin/LibsConfig.kt index 4bf9ffca2..0599a8567 100644 --- a/buildSrc/src/main/kotlin/LibsConfig.kt +++ b/buildSrc/src/main/kotlin/LibsConfig.kt @@ -29,7 +29,7 @@ fun Project.applyLibrariesConfiguration() { applyCommonConfiguration() apply(plugin = "java-base") apply(plugin = "maven-publish") - apply(plugin = "com.github.johnrengelman.shadow") + apply(plugin = "com.gradleup.shadow") apply(plugin = "signing") configurations { diff --git a/buildSrc/src/main/kotlin/PlatformConfig.kt b/buildSrc/src/main/kotlin/PlatformConfig.kt index 8f737e9ce..128e7f09d 100644 --- a/buildSrc/src/main/kotlin/PlatformConfig.kt +++ b/buildSrc/src/main/kotlin/PlatformConfig.kt @@ -20,7 +20,7 @@ fun Project.applyPlatformAndCoreConfiguration() { apply(plugin = "eclipse") apply(plugin = "idea") apply(plugin = "maven-publish") - apply(plugin = "com.github.johnrengelman.shadow") + apply(plugin = "com.gradleup.shadow") apply(plugin = "signing") applyCommonJavaConfiguration( From 3b4e8492765dfc7daca49b80a465335012c90dc6 Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 25 Aug 2024 15:20:07 +0100 Subject: [PATCH 359/466] chore: warn when both history db and delete disk on logout are enabled (#2824) * chore: warn when both history db and delete disk on logout are enabled * Improve message --- .../main/java/com/fastasyncworldedit/core/Fawe.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java index 829f29da6..dac6fe9d6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java @@ -365,6 +365,18 @@ public class Fawe { Settings.settings().QUEUE.PARALLEL_THREADS ); } + if (Settings.settings().HISTORY.DELETE_DISK_ON_LOGOUT && Settings.settings().HISTORY.USE_DATABASE) { + LOGGER.warn("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + LOGGER.warn("!!! !!!"); + LOGGER.warn("!!! Using history database whilst deleting disk history! !!!"); + LOGGER.warn("!!! You will not be able to rollback edits after a user logs !!!"); + LOGGER.warn("!!! out, recommended to disable delete-disk-on-logout if you !!!"); + LOGGER.warn("!!! you want to have full history rollback functionality. !!!"); + LOGGER.warn("!!! Disable use-database if you do not need to have rollback !!!"); + LOGGER.warn("!!! functionality and wish to disable this warning. !!!"); + LOGGER.warn("!!! !!!"); + LOGGER.warn("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + } try { byte[] in = new byte[0]; byte[] compressed = LZ4Factory.fastestJavaInstance().fastCompressor().compress(in); From 2a70622013f1af58b8f1a5e5268cf989dbf306e0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2024 00:42:17 +0000 Subject: [PATCH 360/466] Update bstats to v3.0.3 (#2895) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 927abab42..f78ba625f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ towny = "0.100.3.12" plotsquared = "7.3.9" # Third party -bstats = "3.0.2" +bstats = "3.0.3" sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.17.0" From 75fb1cbee745ff56ca27a90736845ef0aab7d806 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2024 00:42:43 +0000 Subject: [PATCH 361/466] Update dependency paperweight-userdev (#2896) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts | 2 +- worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts index 1512dca87..6aac6f9d9 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/ - the().paperDevBundle("1.20.6-R0.1-20240702.153951-123") + the().paperDevBundle("1.20.6-R0.1-20240824.093908-124") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts index a589c6b09..f7ed71e29 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.1-R0.1-20240818.224341-32") + the().paperDevBundle("1.21.1-R0.1-20240825.214216-48") compileOnly(libs.paperlib) } From f5f9ae6a85dc9b3e075ee4dcc4606751c24cc9b6 Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Thu, 29 Aug 2024 07:18:11 +0200 Subject: [PATCH 362/466] Fix: Copy-Paste-Brush with falsy mask (#2899) * fix: don't attempt to load all possible world chunks when copy pasta brush empty clipboard * chore: move check into ResizableClipboardBuilder --- .../core/extent/clipboard/ResizableClipboardBuilder.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ResizableClipboardBuilder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ResizableClipboardBuilder.java index 05089a111..4efa4f456 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ResizableClipboardBuilder.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ResizableClipboardBuilder.java @@ -58,6 +58,9 @@ public class ResizableClipboardBuilder extends MemoryOptimizedHistory { } public Clipboard build() { + if (longSize() == 0) { + return EmptyClipboard.getInstance(); + } BlockVector3 pos1 = BlockVector3.at(minX, minY, minZ); BlockVector3 pos2 = BlockVector3.at(maxX, maxY, maxZ); CuboidRegion region = new CuboidRegion(pos1, pos2); From 6a0b006da6760d48b72ce18bda52134faad8d37d Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Sun, 1 Sep 2024 12:25:54 +0200 Subject: [PATCH 363/466] fix: hollow on large areas fails (#2900) fix: determine BlockVector3Set by region size for recurse hollow --- .../src/main/java/com/sk89q/worldedit/EditSession.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 926265bfb..4f987bd7e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -3611,7 +3611,8 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { } private void recurseHollow(Region region, BlockVector3 origin, Set outside, Mask mask) { - final LocalBlockVectorSet queue = new LocalBlockVectorSet(); + // FAWE start - use BlockVector3Set instead of LinkedList + final BlockVector3Set queue = BlockVector3Set.getAppropriateVectorSet(region); queue.add(origin); while (!queue.isEmpty()) { @@ -3634,6 +3635,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { } } } + // FAWE end } public int makeBiomeShape( From b4f4fc63b6556fefd2d378075bc8431b3c404dc7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 00:58:45 +0000 Subject: [PATCH 364/466] Update dependency paperweight-userdev to v1.21.1-R0.1-20240901.181116-54 (#2905) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts index f7ed71e29..cffccf99f 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.1-R0.1-20240825.214216-48") + the().paperDevBundle("1.21.1-R0.1-20240901.181116-54") compileOnly(libs.paperlib) } From a369513684ee42b779a00b88b72897eaade077aa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 00:59:03 +0000 Subject: [PATCH 365/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.3.13 (#2904) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f78ba625f..9aabeab5e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.3.12" +towny = "0.100.3.13" plotsquared = "7.3.9" # Third party From 378334bd752e5f3e61352dc50307fe3f4a8bb279 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Tue, 3 Sep 2024 21:39:32 +0200 Subject: [PATCH 366/466] Avoid map lookup in `isMovementBlocker` calls (#2906) --- .../adapter/impl/fawe/v1_20_R2/PaperweightBlockMaterial.java | 3 ++- .../adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java | 3 ++- .../adapter/impl/fawe/v1_20_R4/PaperweightBlockMaterial.java | 3 ++- .../adapter/impl/fawe/v1_21_R1/PaperweightBlockMaterial.java | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightBlockMaterial.java index 2e1dd8279..a50489b93 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightBlockMaterial.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightBlockMaterial.java @@ -135,9 +135,10 @@ public class PaperweightBlockMaterial implements BlockMaterial { return block.isRandomlyTicking(blockState); } + @SuppressWarnings("deprecation") @Override public boolean isMovementBlocker() { - return craftMaterial.isSolid(); + return blockState.blocksMotion(); } @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java index 74b1c035c..857d09aa6 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java @@ -125,9 +125,10 @@ public class PaperweightBlockMaterial implements BlockMaterial { return block.isRandomlyTicking(blockState); } + @SuppressWarnings("deprecation") @Override public boolean isMovementBlocker() { - return craftMaterial.isSolid(); + return blockState.blocksMotion(); } @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightBlockMaterial.java index 9c2292451..e80ecf3cb 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightBlockMaterial.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightBlockMaterial.java @@ -126,9 +126,10 @@ public class PaperweightBlockMaterial implements BlockMaterial { return blockState.isRandomlyTicking(); } + @SuppressWarnings("deprecation") @Override public boolean isMovementBlocker() { - return craftMaterial.isSolid(); + return blockState.blocksMotion(); } @Override diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightBlockMaterial.java index 359527396..537072538 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightBlockMaterial.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightBlockMaterial.java @@ -126,9 +126,10 @@ public class PaperweightBlockMaterial implements BlockMaterial { return blockState.isRandomlyTicking(); } + @SuppressWarnings("deprecation") @Override public boolean isMovementBlocker() { - return craftMaterial.isSolid(); + return blockState.blocksMotion(); } @Override From 4b099d3588ba89c4872914653665774958c5af45 Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Tue, 3 Sep 2024 23:16:00 +0200 Subject: [PATCH 367/466] fix(GriefDefender): invalidate mask on claim change (#2903) --- .../bukkit/regions/GriefDefenderFeature.java | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefDefenderFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefDefenderFeature.java index 9ac2fd68a..f1baf3d9e 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefDefenderFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefDefenderFeature.java @@ -3,7 +3,9 @@ package com.fastasyncworldedit.bukkit.regions; import com.fastasyncworldedit.core.regions.FaweMask; import com.griefdefender.api.GriefDefender; import com.griefdefender.api.claim.Claim; +import com.griefdefender.api.claim.ClaimManager; import com.griefdefender.api.claim.TrustTypes; +import com.griefdefender.lib.flowpowered.math.vector.Vector3i; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; @@ -17,8 +19,8 @@ public class GriefDefenderFeature extends BukkitMaskManager implements Listener private static final Logger LOGGER = LogManagerCompat.getLogger(); - public GriefDefenderFeature(final Plugin GriefDefenderPlugin) { - super(GriefDefenderPlugin.getName()); + public GriefDefenderFeature(final Plugin plugin) { + super(plugin.getName()); LOGGER.info("Plugin 'GriefDefender' found. Using it now."); } @@ -44,9 +46,14 @@ public class GriefDefenderFeature extends BukkitMaskManager implements Listener ); return new FaweMask(new CuboidRegion(pos1, pos2)) { + private final int[] bounds = new int[]{ + pos1.x(), pos1.y(), pos1.z(), + pos2.x(), pos2.y(), pos2.z() + }; + @Override public boolean isValid(com.sk89q.worldedit.entity.Player wePlayer, MaskType type) { - return isAllowed(player, claim, type); + return validateClaimAgainstCache(claim, bounds) && isAllowed(player, claim, type); } }; } @@ -54,4 +61,20 @@ public class GriefDefenderFeature extends BukkitMaskManager implements Listener return null; } + private static boolean validateClaimAgainstCache(Claim claim, int[] bounds) { + Vector3i min = claim.getLesserBoundaryCorner(); + Vector3i max = claim.getGreaterBoundaryCorner(); + if (min.getX() != bounds[0] || min.getY() != bounds[1] || min.getZ() != bounds[2]) { + return false; + } + if (max.getX() != bounds[3] || max.getY() != bounds[4] || max.getZ() != bounds[5]) { + return false; + } + final ClaimManager manager = GriefDefender.getCore().getClaimManager(claim.getWorldUniqueId()); + if (manager == null) { + return false; + } + return manager.getClaimByUUID(claim.getUniqueId()) != null; + } + } From 14446bc853c7dfc0a65f2d3047076197c83669e7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 01:47:18 +0000 Subject: [PATCH 368/466] Update plotsquared to v7.3.10 (#2908) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9aabeab5e..004644b3f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" towny = "0.100.3.13" -plotsquared = "7.3.9" +plotsquared = "7.3.10" # Third party bstats = "3.0.3" From 9cf79d0e3b798ef6a6562e0e22be1345106f36f3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2024 03:15:54 +0000 Subject: [PATCH 369/466] Update dependency paperweight-userdev to v1.21.1-R0.1-20240910.023150-72 (#2907) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts index cffccf99f..4eb949758 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.1-R0.1-20240901.181116-54") + the().paperDevBundle("1.21.1-R0.1-20240910.023150-72") compileOnly(libs.paperlib) } From 5ac4d2fd5f0cba00b58361490bb23032b46bc393 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Tue, 10 Sep 2024 10:39:41 +0200 Subject: [PATCH 370/466] Replace usages and overrides of deprecated getSuggestions method (#2891) --- .../extension/factory/parser/mask/AdjacentMaskParser.java | 4 ++-- .../core/extension/factory/parser/mask/AngleMaskParser.java | 2 +- .../extension/factory/parser/mask/BesideMaskParser.java | 4 ++-- .../extension/factory/parser/mask/ExtremaMaskParser.java | 2 +- .../extension/factory/parser/mask/ROCAngleMaskParser.java | 2 +- .../extension/factory/parser/mask/RadiusMaskParser.java | 2 +- .../extension/factory/parser/mask/RichOffsetMaskParser.java | 4 ++-- .../extension/factory/parser/mask/SimplexMaskParser.java | 2 +- .../factory/parser/mask/SurfaceAngleMaskParser.java | 2 +- .../factory/parser/pattern/AngleColorPatternParser.java | 2 +- .../factory/parser/pattern/AverageColorPatternParser.java | 2 +- .../factory/parser/pattern/BiomePatternParser.java | 2 +- .../factory/parser/pattern/BufferedPattern2DParser.java | 4 ++-- .../factory/parser/pattern/BufferedPatternParser.java | 4 ++-- .../factory/parser/pattern/ColorPatternParser.java | 2 +- .../factory/parser/pattern/DesaturatePatternParser.java | 2 +- .../factory/parser/pattern/Linear2DPatternParser.java | 4 ++-- .../factory/parser/pattern/Linear3DPatternParser.java | 4 ++-- .../factory/parser/pattern/LinearPatternParser.java | 4 ++-- .../factory/parser/pattern/MaskedPatternParser.java | 6 +++--- .../extension/factory/parser/pattern/NoXPatternParser.java | 4 ++-- .../extension/factory/parser/pattern/NoYPatternParser.java | 4 ++-- .../extension/factory/parser/pattern/NoZPatternParser.java | 4 ++-- .../factory/parser/pattern/NoisePatternParser.java | 4 ++-- .../factory/parser/pattern/OffsetPatternParser.java | 4 ++-- .../parser/pattern/RandomFullClipboardPatternParser.java | 3 ++- .../factory/parser/pattern/RandomOffsetPatternParser.java | 4 ++-- .../factory/parser/pattern/RelativePatternParser.java | 4 ++-- .../factory/parser/pattern/SaturatePatternParser.java | 2 +- .../parser/pattern/SolidRandomOffsetPatternParser.java | 4 ++-- .../parser/pattern/SurfaceRandomOffsetPatternParser.java | 4 ++-- .../factory/parser/pattern/TypeSwapPatternParser.java | 2 +- .../factory/parser/transform/Linear3DTransformParser.java | 4 ++-- .../factory/parser/transform/LinearTransformParser.java | 4 ++-- .../factory/parser/transform/OffsetTransformParser.java | 4 ++-- .../factory/parser/transform/PatternTransformParser.java | 6 +++--- .../factory/parser/transform/RotateTransformParser.java | 4 ++-- .../factory/parser/transform/ScaleTransformParser.java | 4 ++-- .../factory/parser/transform/SpreadTransformParser.java | 4 ++-- 39 files changed, 67 insertions(+), 66 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/AdjacentMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/AdjacentMaskParser.java index 8fbcb4ae0..7521eb10a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/AdjacentMaskParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/AdjacentMaskParser.java @@ -19,9 +19,9 @@ public class AdjacentMaskParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index == 0) { - return worldEdit.getMaskFactory().getSuggestions(argumentInput).stream(); + return worldEdit.getMaskFactory().getSuggestions(argumentInput, context).stream(); } else if (index == 1 || index == 2) { return SuggestionHelper.suggestPositiveDoubles(argumentInput); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/AngleMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/AngleMaskParser.java index dfd62b9b8..ea8e36665 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/AngleMaskParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/AngleMaskParser.java @@ -22,7 +22,7 @@ public class AngleMaskParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index == 0 || index == 1) { return SuggestionHelper.suggestPositiveDoubles(argumentInput).flatMap(s -> Stream.of(s, s + "d")); } else if (index > 1 && index <= 1 + flags.length) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/BesideMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/BesideMaskParser.java index 954b9f53d..fd597a216 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/BesideMaskParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/BesideMaskParser.java @@ -18,9 +18,9 @@ public class BesideMaskParser extends RichParser { } @Override - protected Stream getSuggestions(final String argumentInput, final int index) { + protected Stream getSuggestions(final String argumentInput, final int index, ParserContext context) { if (index == 0) { - return worldEdit.getMaskFactory().getSuggestions(argumentInput).stream(); + return worldEdit.getMaskFactory().getSuggestions(argumentInput, context).stream(); } else if (index == 1 || index == 2) { return SuggestionHelper.suggestPositiveDoubles(argumentInput); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/ExtremaMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/ExtremaMaskParser.java index a875ec802..6bab51981 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/ExtremaMaskParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/ExtremaMaskParser.java @@ -22,7 +22,7 @@ public class ExtremaMaskParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index == 0 || index == 1) { return SuggestionHelper.suggestPositiveDoubles(argumentInput).flatMap(s -> Stream.of(s, s + "d")); } else if (index > 1 && index <= 1 + flags.length) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/ROCAngleMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/ROCAngleMaskParser.java index dff4e8f32..00a285b95 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/ROCAngleMaskParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/ROCAngleMaskParser.java @@ -22,7 +22,7 @@ public class ROCAngleMaskParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index == 0 || index == 1) { return SuggestionHelper.suggestPositiveDoubles(argumentInput).flatMap(s -> Stream.of(s, s + "d")); } else if (index > 1 && index <= 1 + flags.length) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RadiusMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RadiusMaskParser.java index 8a57c73af..559b3bab3 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RadiusMaskParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RadiusMaskParser.java @@ -18,7 +18,7 @@ public class RadiusMaskParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index == 0 || index == 1) { return SuggestionHelper.suggestPositiveIntegers(argumentInput); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichOffsetMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichOffsetMaskParser.java index f6a21ef6f..47b56cb56 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichOffsetMaskParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichOffsetMaskParser.java @@ -24,12 +24,12 @@ public class RichOffsetMaskParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index < 3) { return SuggestionHelper.suggestPositiveIntegers(argumentInput); } if (index == 3) { - return worldEdit.getMaskFactory().getSuggestions(argumentInput).stream(); + return worldEdit.getMaskFactory().getSuggestions(argumentInput, context).stream(); } return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/SimplexMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/SimplexMaskParser.java index 4674057b2..f1d2e6c55 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/SimplexMaskParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/SimplexMaskParser.java @@ -20,7 +20,7 @@ public class SimplexMaskParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index < 3) { return SuggestionHelper.suggestPositiveDoubles(argumentInput); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/SurfaceAngleMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/SurfaceAngleMaskParser.java index ab011f412..7a85e708b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/SurfaceAngleMaskParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/SurfaceAngleMaskParser.java @@ -23,7 +23,7 @@ public class SurfaceAngleMaskParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index <= 2) { return SuggestionHelper.suggestPositiveDoubles(argumentInput); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/AngleColorPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/AngleColorPatternParser.java index 7074fdb13..d471435e6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/AngleColorPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/AngleColorPatternParser.java @@ -25,7 +25,7 @@ public class AngleColorPatternParser extends RichParser { } @Override - public Stream getSuggestions(String argumentInput, int index) { + public Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index != 0) { return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/AverageColorPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/AverageColorPatternParser.java index 35d28382d..1fd2e8b2f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/AverageColorPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/AverageColorPatternParser.java @@ -25,7 +25,7 @@ public class AverageColorPatternParser extends RichParser { } @Override - public Stream getSuggestions(String argumentInput, int index) { + public Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index > 4) { return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BiomePatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BiomePatternParser.java index 0adbe2cd7..74e1b5b65 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BiomePatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BiomePatternParser.java @@ -54,7 +54,7 @@ public class BiomePatternParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index == 0) { return BiomeType.REGISTRY.getSuggestions(argumentInput); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPattern2DParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPattern2DParser.java index 246e024c6..4ae760918 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPattern2DParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPattern2DParser.java @@ -26,9 +26,9 @@ public class BufferedPattern2DParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index == 0) { - return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream(); } return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPatternParser.java index 49fd27495..3660aa902 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPatternParser.java @@ -26,9 +26,9 @@ public class BufferedPatternParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index == 0) { - return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream(); } return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/ColorPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/ColorPatternParser.java index 9b424d5eb..0363b2ec5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/ColorPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/ColorPatternParser.java @@ -26,7 +26,7 @@ public class ColorPatternParser extends RichParser { } @Override - public Stream getSuggestions(String argumentInput, int index) { + public Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index > 4) { return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/DesaturatePatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/DesaturatePatternParser.java index 2218f479e..d5ace9036 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/DesaturatePatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/DesaturatePatternParser.java @@ -25,7 +25,7 @@ public class DesaturatePatternParser extends RichParser { } @Override - public Stream getSuggestions(String argumentInput, int index) { + public Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index == 0) { return SuggestionHelper.suggestPositiveDoubles(argumentInput); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear2DPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear2DPatternParser.java index 7da0b2377..3e77a6ef1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear2DPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear2DPatternParser.java @@ -28,9 +28,9 @@ public class Linear2DPatternParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { return switch (index) { - case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream(); case 1, 2 -> SuggestionHelper.suggestPositiveIntegers(argumentInput); default -> Stream.empty(); }; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear3DPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear3DPatternParser.java index cd3a7d8db..7f7ffd7aa 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear3DPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear3DPatternParser.java @@ -28,9 +28,9 @@ public class Linear3DPatternParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { return switch (index) { - case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream(); case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput); default -> Stream.empty(); }; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/LinearPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/LinearPatternParser.java index 785e8261d..e0d5d3105 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/LinearPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/LinearPatternParser.java @@ -28,9 +28,9 @@ public class LinearPatternParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { return switch (index) { - case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream(); case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput); default -> Stream.empty(); }; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/MaskedPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/MaskedPatternParser.java index 3aed039c3..92fcd6f5f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/MaskedPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/MaskedPatternParser.java @@ -25,10 +25,10 @@ public class MaskedPatternParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { return switch (index) { - case 0 -> this.worldEdit.getMaskFactory().getSuggestions(argumentInput).stream(); - case 1, 2 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + case 0 -> this.worldEdit.getMaskFactory().getSuggestions(argumentInput, context).stream(); + case 1, 2 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream(); default -> Stream.empty(); }; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoXPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoXPatternParser.java index 8e3ac729f..915963d4c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoXPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoXPatternParser.java @@ -24,9 +24,9 @@ public class NoXPatternParser extends RichParser { } @Override - public Stream getSuggestions(String argumentInput, int index) { + public Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index == 0) { - return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream(); } return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoYPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoYPatternParser.java index 2cc00c8ad..34e3724a4 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoYPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoYPatternParser.java @@ -24,9 +24,9 @@ public class NoYPatternParser extends RichParser { } @Override - public Stream getSuggestions(String argumentInput, int index) { + public Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index == 0) { - return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream(); } return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoZPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoZPatternParser.java index 927d13d0c..aaa9cf5fd 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoZPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoZPatternParser.java @@ -24,9 +24,9 @@ public class NoZPatternParser extends RichParser { } @Override - public Stream getSuggestions(String argumentInput, int index) { + public Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index == 0) { - return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream(); } return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoisePatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoisePatternParser.java index 37ad97417..d91a66f44 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoisePatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/NoisePatternParser.java @@ -36,12 +36,12 @@ public abstract class NoisePatternParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index == 0) { return SuggestionHelper.suggestPositiveDoubles(argumentInput); } if (index == 1) { - return worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + return worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream(); } return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/OffsetPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/OffsetPatternParser.java index 6ae72c7a0..ff203208c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/OffsetPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/OffsetPatternParser.java @@ -25,9 +25,9 @@ public class OffsetPatternParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { return switch (index) { - case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream(); case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput); default -> Stream.empty(); }; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomFullClipboardPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomFullClipboardPatternParser.java index 2af68adc8..587d8d81f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomFullClipboardPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomFullClipboardPatternParser.java @@ -4,6 +4,7 @@ import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.extension.factory.parser.RichParser; import com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder; import com.fastasyncworldedit.core.function.pattern.RandomFullClipboardPattern; +import com.google.common.base.Function; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.util.SuggestionHelper; import com.sk89q.worldedit.extension.input.InputParseException; @@ -33,7 +34,7 @@ public class RandomFullClipboardPatternParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { switch (index) { case 0: if (argumentInput.equals("#") || argumentInput.equals("#c")) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomOffsetPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomOffsetPatternParser.java index 2486ef119..6d910b0eb 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomOffsetPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RandomOffsetPatternParser.java @@ -25,9 +25,9 @@ public class RandomOffsetPatternParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { return switch (index) { - case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream(); case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput); default -> Stream.empty(); }; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RelativePatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RelativePatternParser.java index bf56c1ddb..43c4d0fbf 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RelativePatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/RelativePatternParser.java @@ -24,9 +24,9 @@ public class RelativePatternParser extends RichParser { } @Override - public Stream getSuggestions(String argumentInput, int index) { + public Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index == 0) { - return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream(); } return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SaturatePatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SaturatePatternParser.java index bb40f029d..e93521529 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SaturatePatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SaturatePatternParser.java @@ -25,7 +25,7 @@ public class SaturatePatternParser extends RichParser { } @Override - public Stream getSuggestions(String argumentInput, int index) { + public Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index > 3) { return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SolidRandomOffsetPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SolidRandomOffsetPatternParser.java index 618c463d6..ebc6b74b5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SolidRandomOffsetPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SolidRandomOffsetPatternParser.java @@ -25,9 +25,9 @@ public class SolidRandomOffsetPatternParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { return switch (index) { - case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream(); case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput); default -> Stream.empty(); }; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SurfaceRandomOffsetPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SurfaceRandomOffsetPatternParser.java index aa28b11d8..31a7060d5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SurfaceRandomOffsetPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/SurfaceRandomOffsetPatternParser.java @@ -25,9 +25,9 @@ public class SurfaceRandomOffsetPatternParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { return switch (index) { - case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream(); case 1 -> SuggestionHelper.suggestPositiveIntegers(argumentInput); default -> Stream.empty(); }; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/TypeSwapPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/TypeSwapPatternParser.java index 5bf33d3a0..1c4d25b91 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/TypeSwapPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/TypeSwapPatternParser.java @@ -28,7 +28,7 @@ public class TypeSwapPatternParser extends RichParser { } @Override - public Stream getSuggestions(String argumentInput, int index) { + public Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index > 2) { return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/Linear3DTransformParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/Linear3DTransformParser.java index 01d4868d3..ef72110c4 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/Linear3DTransformParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/Linear3DTransformParser.java @@ -23,9 +23,9 @@ public class Linear3DTransformParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index == 0) { - return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream(); + return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream(); } return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/LinearTransformParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/LinearTransformParser.java index 026f38338..fb646b56b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/LinearTransformParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/LinearTransformParser.java @@ -23,9 +23,9 @@ public class LinearTransformParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index == 0) { - return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream(); + return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream(); } return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/OffsetTransformParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/OffsetTransformParser.java index 471359b78..3aeebfd45 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/OffsetTransformParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/OffsetTransformParser.java @@ -26,11 +26,11 @@ public class OffsetTransformParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index < 3) { return SuggestionHelper.suggestPositiveIntegers(argumentInput); } else if (index == 3) { - return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream(); + return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream(); } return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/PatternTransformParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/PatternTransformParser.java index cf81db4ce..6405fa5ec 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/PatternTransformParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/PatternTransformParser.java @@ -24,11 +24,11 @@ public class PatternTransformParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index == 0) { - return worldEdit.getPatternFactory().getSuggestions(argumentInput).stream(); + return worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream(); } else if (index == 1) { - return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream(); + return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream(); } return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/RotateTransformParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/RotateTransformParser.java index 19ae8a599..c7f756efd 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/RotateTransformParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/RotateTransformParser.java @@ -25,12 +25,12 @@ public class RotateTransformParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index < 3) { return SuggestionHelper.suggestPositiveDoubles(argumentInput); } if (index == 3) { - return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream(); + return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream(); } return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/ScaleTransformParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/ScaleTransformParser.java index 4bab68d0f..028c79f05 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/ScaleTransformParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/ScaleTransformParser.java @@ -24,11 +24,11 @@ public class ScaleTransformParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index < 3) { return SuggestionHelper.suggestPositiveDoubles(argumentInput); } else if (index == 3) { - return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream(); + return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream(); } return Stream.empty(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/SpreadTransformParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/SpreadTransformParser.java index 2f71407b2..b2ad0acbd 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/SpreadTransformParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/transform/SpreadTransformParser.java @@ -24,11 +24,11 @@ public class SpreadTransformParser extends RichParser { } @Override - protected Stream getSuggestions(String argumentInput, int index) { + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { if (index < 3) { return SuggestionHelper.suggestPositiveIntegers(argumentInput); } else if (index == 3) { - return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream(); + return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream(); } return Stream.empty(); } From f771b0cf907c1457c71c9d9f580563645a2526af Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Wed, 11 Sep 2024 22:27:12 +0200 Subject: [PATCH 371/466] fix: don't process out of bound section while trimming Y sections (#2902) * fix: don't process out of bound section while trimming Y sections * fix: handle upper sections * "fix" macos tests? * cleanup imports * update test case(s), fix upper bound(?) * chore: simplify trim logic --- .../core/queue/IBatchProcessor.java | 59 ++++---- .../core/queue/IBatchProcessorTest.java | 136 ++++++++++++++++++ 2 files changed, 166 insertions(+), 29 deletions(-) create mode 100644 worldedit-core/src/test/java/com/fastasyncworldedit/core/queue/IBatchProcessorTest.java diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java index 4ba91a4f3..6b81b61f7 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java @@ -62,40 +62,41 @@ public interface IBatchProcessor { * @return false if chunk is empty of blocks */ default boolean trimY(IChunkSet set, int minY, int maxY, final boolean keepInsideRange) { - int minLayer = (minY - 1) >> 4; - int maxLayer = (maxY + 1) >> 4; + int minLayer = minY >> 4; + int maxLayer = maxY >> 4; if (keepInsideRange) { - for (int layer = set.getMinSectionPosition(); layer <= minLayer; layer++) { - if (set.hasSection(layer)) { - if (layer == minLayer) { - char[] arr = set.loadIfPresent(layer); - if (arr != null) { - int index = (minY & 15) << 8; - for (int i = 0; i < index; i++) { - arr[i] = BlockTypesCache.ReservedIDs.__RESERVED__; - } - set.setBlocks(layer, arr); - } - } else { - set.setBlocks(layer, null); + for (int layer = set.getMinSectionPosition(); layer <= set.getMaxSectionPosition(); layer++) { + if (!set.hasSection(layer)) { + continue; + } + // wipe all data from chunk layers above or below the max / min layer + if (layer < minLayer || layer > maxLayer) { + set.setBlocks(layer, null); + continue; + } + // if chunk layer / section is fully enclosed by minY to maxY, keep as is + if (layer > minLayer && layer < maxLayer) { + continue; + } + char[] blocks = set.loadIfPresent(layer); + if (blocks == null) { + continue; + } + // When on the minimum layer (as defined by minY), remove blocks up to minY (exclusive) + if (layer == minLayer) { + int index = (minY & 15) << 8; + for (int i = 0; i < index; i++) { + blocks[i] = BlockTypesCache.ReservedIDs.__RESERVED__; } } - } - for (int layer = maxLayer; layer <= set.getMaxSectionPosition(); layer++) { - if (set.hasSection(layer)) { - if (layer == maxLayer) { - char[] arr = set.loadIfPresent(layer); - if (arr != null) { - int index = ((maxY + 1) & 15) << 8; - for (int i = index; i < arr.length; i++) { - arr[i] = BlockTypesCache.ReservedIDs.__RESERVED__; - } - set.setBlocks(layer, arr); - } - } else { - set.setBlocks(layer, null); + // When on the maximum layer (as defined by maxY), remove blocks above maxY (exclusive) + if (layer == maxLayer) { + int index = ((maxY & 15) + 1) << 8; + for (int i = index; i < blocks.length; i++) { + blocks[i] = BlockTypesCache.ReservedIDs.__RESERVED__; } } + set.setBlocks(layer, blocks); } try { int layer = (minY - 15) >> 4; diff --git a/worldedit-core/src/test/java/com/fastasyncworldedit/core/queue/IBatchProcessorTest.java b/worldedit-core/src/test/java/com/fastasyncworldedit/core/queue/IBatchProcessorTest.java new file mode 100644 index 000000000..e28d0d236 --- /dev/null +++ b/worldedit-core/src/test/java/com/fastasyncworldedit/core/queue/IBatchProcessorTest.java @@ -0,0 +1,136 @@ +package com.fastasyncworldedit.core.queue; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import org.jetbrains.annotations.Nullable; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.parallel.Isolated; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.Arrays; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class IBatchProcessorTest { + + @Nested + @Isolated + class trimY { + + private static final char[] CHUNK_DATA = new char[16 * 16 * 16]; + private static final char[] SLICE_AIR = new char[16 * 16]; + private static final char[] SLICE_RESERVED = new char[16 * 16]; + private final IBatchProcessor processor = new NoopBatchProcessor(); + + static { + Arrays.fill(CHUNK_DATA, (char) BlockTypesCache.ReservedIDs.AIR); + Arrays.fill(SLICE_AIR, (char) BlockTypesCache.ReservedIDs.AIR); + Arrays.fill(SLICE_RESERVED, (char) BlockTypesCache.ReservedIDs.__RESERVED__); + } + + @ParameterizedTest + @MethodSource("provideTrimYInBoundsParameters") + void testFullChunkSelectedInBoundedRegion(int minY, int maxY, int minSection, int maxSection) { + final IChunkSet set = mock(); + + char[][] sections = new char[(320 + 64) >> 4][CHUNK_DATA.length]; + for (final char[] chars : sections) { + System.arraycopy(CHUNK_DATA, 0, chars, 0, CHUNK_DATA.length); + } + + when(set.getMinSectionPosition()).thenReturn(-64 >> 4); + when(set.getMaxSectionPosition()).thenReturn(319 >> 4); + when(set.hasSection(anyInt())).thenReturn(true); + when(set.loadIfPresent(anyInt())).thenAnswer(invocationOnMock -> sections[invocationOnMock.getArgument(0) + 4]); + doAnswer(invocationOnMock -> { + sections[invocationOnMock.getArgument(0) + 4] = invocationOnMock.getArgument(1); + return null; + }).when(set).setBlocks(anyInt(), any()); + + processor.trimY(set, minY, maxY, true); + + + for (int section = -64 >> 4; section < 320 >> 4; section++) { + int sectionIndex = section + 4; + char[] palette = sections[sectionIndex]; + if (section < minSection) { + assertNull(palette, "expected section below minimum section to be null"); + continue; + } + if (section > maxSection) { + assertNull(palette, "expected section above maximum section to be null"); + continue; + } + if (section == minSection) { + for (int slice = 0; slice < 16; slice++) { + boolean shouldContainBlocks = slice >= (minY % 16); + // If boundaries only span one section, the upper constraints have to be checked explicitly + if (section == maxSection) { + shouldContainBlocks &= slice <= (maxY % 16); + } + assertArrayEquals( + shouldContainBlocks ? SLICE_AIR : SLICE_RESERVED, + Arrays.copyOfRange(palette, slice << 8, (slice + 1) << 8), + ("[lower] slice %d (y=%d) expected to contain " + (shouldContainBlocks ? "air" : "nothing")) + .formatted(slice, ((section << 4) + slice)) + ); + } + continue; + } + if (section == maxSection) { + for (int slice = 0; slice < 16; slice++) { + boolean shouldContainBlocks = slice <= (maxY % 16); + assertArrayEquals( + shouldContainBlocks ? SLICE_AIR : SLICE_RESERVED, + Arrays.copyOfRange(palette, slice << 8, (slice + 1) << 8), + ("[upper] slice %d (y=%d) expected to contain " + (shouldContainBlocks ? "air" : "nothing")) + .formatted(slice, ((section << 4) + slice)) + ); + } + continue; + } + assertArrayEquals(CHUNK_DATA, palette, "full captured chunk @ %d should contain full data".formatted(section)); + } + + } + + /** + * Arguments explained: + * 1. minimum y coordinate (inclusive) + * 2. maximum y coordinate (inclusive) + * 3. chunk section which contains minimum y coordinate + * 4. chunk section which contains maximum y coordinate + */ + private static Stream provideTrimYInBoundsParameters() { + return Stream.of( + Arguments.of(64, 72, 4, 4), + Arguments.of(-64, 0, -4, 0), + Arguments.of(0, 128, 0, 8), + Arguments.of(16, 132, 1, 8), + Arguments.of(4, 144, 0, 9), + Arguments.of(12, 255, 0, 15), + Arguments.of(24, 103, 1, 6) + ); + } + + } + + private static final class NoopBatchProcessor implements IBatchProcessor { + + @Override + public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) { + return set; + } + + @Override + public @Nullable Extent construct(final Extent child) { + return null; + } + + } + +} From a1bea11c80cad4b19d8fae519560bc1e1668a15b Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Wed, 11 Sep 2024 22:27:21 +0200 Subject: [PATCH 372/466] fix: allow webinterface schematic format to be detected (#2901) * fix: allow webinterface schematic format to be detected * chore: address review --- .../core/util/MainUtil.java | 4 +- .../worldedit/command/SchematicCommands.java | 62 ++++++++++++------- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java index 0c323e47b..8ab673b77 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java @@ -701,7 +701,7 @@ public class MainUtil { public static File resolve(File dir, String filename, @Nullable ClipboardFormat format, boolean allowDir) { if (format != null) { - if (!filename.matches(".*\\.[\\w].*")) { + if (!filename.matches(".*\\.\\w.*")) { filename = filename + "." + format.getPrimaryFileExtension(); } return MainUtil.resolveRelative(new File(dir, filename)); @@ -712,7 +712,7 @@ public class MainUtil { return file; } } - if (filename.matches(".*\\.[\\w].*")) { + if (filename.matches(".*\\.\\w.*")) { File file = MainUtil.resolveRelative(new File(dir, filename)); if (file.exists()) { return file; 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 615702a19..1b818786a 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 @@ -69,18 +69,18 @@ import org.enginehub.piston.exception.StopExecutionException; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; +import java.io.Closeable; +import java.io.EOFException; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; import java.io.OutputStream; +import java.net.URI; +import java.net.URL; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; @@ -91,8 +91,8 @@ import java.util.Map; import java.util.Objects; import java.util.UUID; import java.util.concurrent.Callable; -import java.util.function.Consumer; import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Consumer; import java.util.function.Function; import java.util.regex.Pattern; @@ -326,13 +326,13 @@ public class SchematicCommands { //FAWE start ClipboardFormat format; - InputStream in = null; + InputStream in; // if format is set explicitly, do not look up by extension! boolean noExplicitFormat = formatName == null; if (noExplicitFormat) { formatName = "fast"; } - try { + try(final Closer closer = Closer.create()) { URI uri; if (formatName.startsWith("url:")) { String t = filename; @@ -346,11 +346,31 @@ public class SchematicCommands { } UUID uuid = UUID.fromString(filename.substring(4)); URL webUrl = new URL(Settings.settings().WEB.URL); - format = ClipboardFormats.findByAlias(formatName); + if ((format = ClipboardFormats.findByAlias(formatName)) == null) { + actor.print(Caption.of("worldedit.schematic.unknown-format", TextComponent.of(formatName))); + return; + } + // The interface requires the correct schematic extension - otherwise it can't be downloaded + // So it basically only supports .schem files (sponge v2 + v3) - or the correct extensions is specified manually + // Sadly it's not really an API endpoint but spits out the HTML source of the uploader - so no real handling + // can happen URL url = new URL(webUrl, "uploads/" + uuid + "." + format.getPrimaryFileExtension()); - ReadableByteChannel byteChannel = Channels.newChannel(url.openStream()); - in = Channels.newInputStream(byteChannel); - uri = url.toURI(); + final Path temp = Files.createTempFile("faweremoteschem", null); + final File tempFile = temp.toFile(); + // delete temporary file when we're done + closer.register((Closeable) () -> Files.deleteIfExists(temp)); + // write schematic into temporary file + try (final InputStream urlIn = new BufferedInputStream(url.openStream()); + final OutputStream tempOut = new BufferedOutputStream(new FileOutputStream(tempFile))) { + urlIn.transferTo(tempOut); + } + // No format is specified -> try or fail + if (noExplicitFormat && (format = ClipboardFormats.findByFile(tempFile)) == null) { + actor.print(Caption.of("fawe.worldedit.schematic.schematic.load-failure", TextComponent.of(filename))); + return; + } + in = new FileInputStream(tempFile); + uri = temp.toUri(); } else { File saveDir = worldEdit.getWorkingDirectoryPath(config.saveDir).toFile(); File dir = Settings.settings().PATHS.PER_PLAYER_SCHEMATICS ? new File(saveDir, actor.getUniqueId().toString()) : saveDir; @@ -378,7 +398,7 @@ public class SchematicCommands { } if (!noExplicitFormat) { format = ClipboardFormats.findByAlias(formatName); - } else if (filename.matches(".*\\.[\\w].*")) { + } else if (filename.matches(".*\\.\\w.*")) { format = ClipboardFormats .findByExplicitExtension(filename.substring(filename.lastIndexOf('.') + 1)); } else { @@ -412,6 +432,7 @@ public class SchematicCommands { in = new FileInputStream(file); uri = file.toURI(); } + closer.register(in); format.hold(actor, uri, in); if (randomRotate) { AffineTransform transform = new AffineTransform(); @@ -422,19 +443,18 @@ public class SchematicCommands { actor.print(Caption.of("fawe.worldedit.schematic.schematic.loaded", filename)); } catch (IllegalArgumentException e) { actor.print(Caption.of("worldedit.schematic.unknown-filename", TextComponent.of(filename))); - } catch (URISyntaxException | IOException e) { + } catch (EOFException e) { + // EOFException is extending IOException - but the IOException error is too generic. + // EOF mostly occurs when there was unexpected content in the schematic - due to the wrong reader (= version) + actor.print(Caption.of("fawe.worldedit.schematic.schematic.load-failure", + TextComponent.of(e.getMessage() != null ? e.getMessage() : "EOFException"))); // often null... + LOGGER.error("Error loading a schematic", e); + } catch (IOException e) { actor.print(Caption.of("worldedit.schematic.file-not-exist", TextComponent.of(Objects.toString(e.getMessage())))); LOGGER.warn("Failed to load a saved clipboard", e); } catch (Exception e) { actor.print(Caption.of("fawe.worldedit.schematic.schematic.load-failure", TextComponent.of(e.getMessage()))); LOGGER.error("Error loading a schematic", e); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException ignored) { - } - } } //FAWE end } From 766a5d6da247d69bca5baa9ff0697fa226dc91bd Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Wed, 11 Sep 2024 22:27:29 +0200 Subject: [PATCH 373/466] Faster undo operations (#2898) --- .../core/configuration/Settings.java | 7 + .../core/history/change/ChangePopulator.java | 65 ++++ .../history/changeset/AbstractChangeSet.java | 8 + .../changeset/AbstractDelegateChangeSet.java | 5 + .../changeset/ChangeExchangeCoordinator.java | 50 +++ .../changeset/FaweStreamChangeSet.java | 286 ++++++++++++++++++ .../core/history/changeset/NullChangeSet.java | 11 + .../function/operation/ChangeSetExecutor.java | 31 +- 8 files changed, 461 insertions(+), 2 deletions(-) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/ChangePopulator.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/ChangeExchangeCoordinator.java diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index 3b80dcdfa..4db469187 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -622,6 +622,13 @@ public class Settings extends Config { }) public static class EXPERIMENTAL { + @Comment({ + "Undo operation batch size", + " - The size defines the number of changes read at once.", + " - Larger numbers might reduce overhead but increase latency for edits with only few changes.", + " - 0 means undo operations are not batched."}) + public int UNDO_BATCH_SIZE = 128; + @Comment({ "[UNSAFE] Directly modify the region files. (OBSOLETE - USE ANVIL COMMANDS)", " - IMPROPER USE CAN CAUSE WORLD CORRUPTION!", diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/ChangePopulator.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/ChangePopulator.java new file mode 100644 index 000000000..6831a443c --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/ChangePopulator.java @@ -0,0 +1,65 @@ +package com.fastasyncworldedit.core.history.change; + +import com.sk89q.worldedit.history.change.Change; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @since TODO + */ +@ApiStatus.Internal +public interface ChangePopulator { + + static ChangePopulator empty() { + class Empty implements ChangePopulator { + private static final Empty EMPTY = new Empty(); + + @Override + public @NotNull C create() { + throw new UnsupportedOperationException("empty"); + } + + @Override + public @Nullable C populate(@NotNull final C change) { + return null; + } + + @Override + public @Nullable C updateOrCreate(@Nullable final Change change) { + return null; + } + + @Override + public boolean accepts(final Change change) { + return false; + } + } + return Empty.EMPTY; + } + + @SuppressWarnings("unchecked") + default @NotNull C update(@Nullable Change before) { + if (accepts(before)) { + return (C) before; + } + return create(); + } + + @NotNull + C create(); + + @Nullable + default C updateOrCreate(@Nullable Change change) { + C u = update(change); + return populate(u); + } + + @Nullable + C populate(@NotNull C change); + + @Contract("null->false") + boolean accepts(Change change); + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java index 346543a0b..84c1193eb 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java @@ -32,6 +32,7 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypesCache; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.ApiStatus; import java.io.IOException; import java.util.Iterator; @@ -250,6 +251,13 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { return getIterator(redo); } + /** + * {@return a coordinator to exchange sets of changes between a producer and a consumer} + * @since TODO + */ + @ApiStatus.Internal + public abstract ChangeExchangeCoordinator getCoordinatedChanges(BlockBag blockBag, int mode, boolean dir); + public abstract Iterator getIterator(boolean redo); public EditSession toEditSession(Actor actor) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractDelegateChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractDelegateChangeSet.java index a44e73013..f3f0cdae4 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractDelegateChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractDelegateChangeSet.java @@ -76,6 +76,11 @@ public class AbstractDelegateChangeSet extends AbstractChangeSet { return parent.getIterator(blockBag, mode, redo); } + @Override + public ChangeExchangeCoordinator getCoordinatedChanges(final BlockBag blockBag, final int mode, final boolean dir) { + return parent.getCoordinatedChanges(blockBag, mode, dir); + } + @Override public Iterator getIterator(boolean redo) { return parent.getIterator(redo); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/ChangeExchangeCoordinator.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/ChangeExchangeCoordinator.java new file mode 100644 index 000000000..56d47500f --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/ChangeExchangeCoordinator.java @@ -0,0 +1,50 @@ +package com.fastasyncworldedit.core.history.changeset; + +import com.sk89q.worldedit.history.change.Change; +import org.jetbrains.annotations.ApiStatus; + +import java.util.concurrent.Exchanger; +import java.util.function.BiConsumer; + +/** + * @since TODO + */ +@ApiStatus.Internal +public class ChangeExchangeCoordinator implements AutoCloseable { + + private static final Thread.Builder.OfVirtual UNDO_VIRTUAL_THREAD_BUILDER = Thread.ofVirtual() + .name("FAWE undo", 0); + private final Exchanger exchanger; + private final BiConsumer, Change[]> runnerTask; + private boolean started = false; + private Thread runner; + + public ChangeExchangeCoordinator(BiConsumer, Change[]> runner) { + this.runnerTask = runner; + this.exchanger = new Exchanger<>(); + } + + public Change[] take(Change[] consumed) { + if (!this.started) { + this.started = true; + final int length = consumed.length; + this.runner = UNDO_VIRTUAL_THREAD_BUILDER + .start(() -> this.runnerTask.accept(this.exchanger, new Change[length])); + } + try { + return exchanger.exchange(consumed); + } catch (InterruptedException e) { + this.runner.interrupt(); + Thread.currentThread().interrupt(); + return null; + } + } + + @Override + public void close() { + if (this.runner != null) { + this.runner.interrupt(); + } + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java index e7132bf5a..211a71303 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java @@ -1,6 +1,7 @@ package com.fastasyncworldedit.core.history.changeset; import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.history.change.ChangePopulator; import com.fastasyncworldedit.core.history.change.MutableBiomeChange; import com.fastasyncworldedit.core.history.change.MutableBlockChange; import com.fastasyncworldedit.core.history.change.MutableEntityChange; @@ -20,15 +21,22 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockTypes; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayDeque; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; +import java.util.List; import java.util.NoSuchElementException; +import java.util.Queue; +import java.util.concurrent.Exchanger; +import java.util.function.BiConsumer; /** * FAWE stream ChangeSet offering support for extended-height worlds @@ -711,6 +719,284 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { } } + @Override + public ChangeExchangeCoordinator getCoordinatedChanges(BlockBag blockBag, int mode, boolean dir) { + try { + return coordinatedChanges(blockBag, mode, dir); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private ChangeExchangeCoordinator coordinatedChanges(final BlockBag blockBag, final int mode, boolean dir) throws IOException { + close(); + var tileCreate = tileChangePopulator(getTileCreateIS(), true); + var tileRemove = tileChangePopulator(getTileRemoveIS(), false); + + var entityCreate = entityChangePopulator(getEntityCreateIS(), true); + var entityRemove = entityChangePopulator(getEntityRemoveIS(), false); + + var blockChange = blockBag != null && mode > 0 ? fullBlockChangePopulator(blockBag, mode, dir) : blockChangePopulator(dir); + + var biomeChange = biomeChangePopulator(dir); + + Queue> populators = new ArrayDeque<>(List.of( + tileCreate, + tileRemove, + entityCreate, + entityRemove, + blockChange, + biomeChange + )); + BiConsumer, Change[]> task = (exchanger, array) -> { + while (fillArray(array, populators)) { + try { + array = exchanger.exchange(array); + } catch (InterruptedException e) { + return; + } + } + }; + return new ChangeExchangeCoordinator(task); + } + + private boolean fillArray(Change[] changes, Queue> populators) { + ChangePopulator populator = populators.peek(); + if (populator == null) { + return false; + } + for (int i = 0; i < changes.length; i++) { + Change change = changes[i]; + do { + change = populator.updateOrCreate(change); + if (change == null) { + populators.remove(); + populator = populators.peek(); + if (populator == null) { + changes[i] = null; // mark end + return true; // still needs to consume the elements of the current round + } + } else { + break; + } + } while (true); + changes[i] = change; + } + return true; + } + + private static abstract class CompoundTagPopulator implements ChangePopulator { + private final NBTInputStream inputStream; + + private CompoundTagPopulator(final NBTInputStream stream) { + inputStream = stream; + } + + @Override + public @Nullable C populate(final @NotNull C change) { + try { + write(change, (CompoundTag) inputStream.readTag()); + return change; + } catch (Exception ignored) { + } + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + protected abstract void write(C change, CompoundTag tag); + } + + private ChangePopulator tileChangePopulator(NBTInputStream is, boolean create) { + if (is == null) { + return ChangePopulator.empty(); + } + class Populator extends CompoundTagPopulator { + + private Populator() { + super(is); + } + + @Override + public @NotNull MutableTileChange create() { + return new MutableTileChange(null, create); + } + + @Override + protected void write(final MutableTileChange change, final CompoundTag tag) { + change.tag = tag; + } + + @Override + public boolean accepts(final Change change) { + return change instanceof MutableTileChange; + } + + } + return new Populator(); + } + private ChangePopulator entityChangePopulator(NBTInputStream is, boolean create) { + if (is == null) { + return ChangePopulator.empty(); + } + class Populator extends CompoundTagPopulator { + + private Populator() { + super(is); + } + + @Override + public @NotNull MutableEntityChange create() { + return new MutableEntityChange(null, create); + } + + @Override + protected void write(final MutableEntityChange change, final CompoundTag tag) { + change.tag = tag; + } + + @Override + public boolean accepts(final Change change) { + return change instanceof MutableTileChange; + } + + } + return new Populator(); + } + + private ChangePopulator fullBlockChangePopulator(BlockBag blockBag, int mode, boolean dir) throws + IOException { + final FaweInputStream is = getBlockIS(); + if (is == null) { + return ChangePopulator.empty(); + } + class Populator implements ChangePopulator { + + @Override + public @NotNull MutableFullBlockChange create() { + return new MutableFullBlockChange(blockBag, mode, dir); + } + + @Override + public @Nullable MutableFullBlockChange populate(@NotNull final MutableFullBlockChange change) { + try { + change.x = posDel.readX(is) + originX; + change.y = posDel.readY(is); + change.z = posDel.readZ(is) + originZ; + idDel.readCombined(is, change); + return change; + } catch (EOFException ignored) { + } catch (Exception e) { + e.printStackTrace(); + } + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public boolean accepts(final Change change) { + return change instanceof MutableFullBlockChange; + } + + } + return new Populator(); + + } + + private ChangePopulator blockChangePopulator(boolean dir) throws IOException { + final FaweInputStream is = getBlockIS(); + if (is == null) { + return ChangePopulator.empty(); + } + class Populator implements ChangePopulator { + + @Override + public @NotNull MutableBlockChange create() { + return new MutableBlockChange(0, 0, 0, BlockTypes.AIR.getInternalId()); + } + + @Override + public @Nullable MutableBlockChange populate(@NotNull final MutableBlockChange change) { + try { + change.x = posDel.readX(is) + originX; + change.y = posDel.readY(is); + change.z = posDel.readZ(is) + originZ; + idDel.readCombined(is, change, dir); + return change; + } catch (EOFException ignored) { + } catch (Exception e) { + e.printStackTrace(); + } + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public boolean accepts(final Change change) { + return change instanceof MutableBlockChange; + } + + } + return new Populator(); + } + + private ChangePopulator biomeChangePopulator(boolean dir) throws IOException { + final FaweInputStream is = getBiomeIS(); + if (is == null) { + return ChangePopulator.empty(); + } + class Populator implements ChangePopulator { + + @Override + public @NotNull MutableBiomeChange create() { + return new MutableBiomeChange(); + } + + @Override + public @Nullable MutableBiomeChange populate(@NotNull final MutableBiomeChange change) { + try { + int int1 = is.read(); + if (int1 != -1) { + int x = ((int1 << 24) + (is.read() << 16) + (is.read() << 8) + is.read()) << 2; + int z = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + is.read()) << 2; + int y = (is.read() - 128) << 2; + int from = is.readVarInt(); + int to = is.readVarInt(); + change.setBiome(x, y, z, from, to); + return change; + } + } catch (EOFException ignored) { + } catch (Exception e) { + e.printStackTrace(); + } + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public boolean accepts(final Change change) { + return change instanceof MutableBiomeChange; + } + + } + return new Populator(); + } + @Override public Iterator getIterator(final boolean dir) { try { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/NullChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/NullChangeSet.java index dd4fddf1a..2a60b3913 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/NullChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/NullChangeSet.java @@ -54,6 +54,17 @@ public class NullChangeSet extends AbstractChangeSet { return getIterator(redo); } + @Override + public ChangeExchangeCoordinator getCoordinatedChanges(final BlockBag blockBag, final int mode, final boolean dir) { + return new ChangeExchangeCoordinator(((exchanger, changes) -> { + try { + exchanger.exchange(null); + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + } + })); + } + @Override public final Iterator getIterator(boolean undo) { return Collections.emptyIterator(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/ChangeSetExecutor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/ChangeSetExecutor.java index 12359fdee..ea52bf335 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/ChangeSetExecutor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/ChangeSetExecutor.java @@ -19,7 +19,9 @@ package com.sk89q.worldedit.function.operation; +import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.history.changeset.AbstractChangeSet; +import com.fastasyncworldedit.core.history.changeset.ChangeExchangeCoordinator; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.history.UndoContext; @@ -56,6 +58,7 @@ public class ChangeSetExecutor implements Operation { //FAWE end private final Iterator iterator; + private final ChangeExchangeCoordinator changeExchangeCoordinator; private final Type type; private final UndoContext context; @@ -74,18 +77,42 @@ public class ChangeSetExecutor implements Operation { this.type = type; this.context = context; - if (changeSet instanceof AbstractChangeSet) { - iterator = ((AbstractChangeSet) changeSet).getIterator(blockBag, inventory, type == Type.REDO); + if (changeSet instanceof AbstractChangeSet abstractChangeSet) { + if (Settings.settings().EXPERIMENTAL.UNDO_BATCH_SIZE > 0) { + this.changeExchangeCoordinator = abstractChangeSet.getCoordinatedChanges(blockBag, inventory, type == Type.REDO); + this.iterator = null; + } else { + this.iterator = abstractChangeSet.getIterator(blockBag, inventory, type == Type.REDO); + this.changeExchangeCoordinator = null; + } } else if (type == Type.UNDO) { iterator = changeSet.backwardIterator(); + this.changeExchangeCoordinator = null; } else { iterator = changeSet.forwardIterator(); + this.changeExchangeCoordinator = null; } } //FAWE end @Override public Operation resume(RunContext run) throws WorldEditException { + // FAWE start - ChangeExchangeCoordinator + if (this.changeExchangeCoordinator != null) { + try (this.changeExchangeCoordinator) { + Change[] changes = new Change[Settings.settings().EXPERIMENTAL.UNDO_BATCH_SIZE]; + while ((changes = this.changeExchangeCoordinator.take(changes)) != null) { + for (final Change change : changes) { + if (change == null) { + return null; // end + } + type.perform(change, context); + } + } + return null; + } + } + // FAWE end while (iterator.hasNext()) { Change change = iterator.next(); //FAWE start - types > individual history step From 19370a354959bac707a5bf122e7646dccb619b39 Mon Sep 17 00:00:00 2001 From: Jordan Date: Sat, 14 Sep 2024 09:47:07 +0100 Subject: [PATCH 374/466] fix: account for spigot having private PalettedContainer#get(int) (#2910) --- .../fawe/v1_20_R2/PaperweightGetBlocks_Copy.java | 15 +++++++++++++-- .../fawe/v1_20_R2/PaperweightPlatformAdapter.java | 9 +++++++++ .../fawe/v1_20_R3/PaperweightGetBlocks_Copy.java | 15 +++++++++++++-- .../fawe/v1_20_R3/PaperweightPlatformAdapter.java | 9 +++++++++ .../fawe/v1_20_R4/PaperweightGetBlocks_Copy.java | 15 +++++++++++++-- .../fawe/v1_20_R4/PaperweightPlatformAdapter.java | 9 +++++++++ .../fawe/v1_21_R1/PaperweightGetBlocks_Copy.java | 15 +++++++++++++-- .../fawe/v1_21_R1/PaperweightPlatformAdapter.java | 9 +++++++++ 8 files changed, 88 insertions(+), 8 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java index b6f4c7d94..26a551f2a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java @@ -15,6 +15,7 @@ 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.BlockTypesCache; +import io.papermc.lib.PaperLib; import net.minecraft.core.Holder; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; @@ -179,8 +180,18 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { biomes[layer] = new Holder[64]; } if (biomeData instanceof PalettedContainer> palettedContainer) { - for (int i = 0; i < 64; i++) { - biomes[layer][i] = palettedContainer.get(i); + if (PaperLib.isPaper()) { + for (int i = 0; i < 64; i++) { + biomes[layer][i] = palettedContainer.get(i); // Only public on paper + } + } else { + try { + for (int i = 0; i < 64; i++) { + biomes[layer][i] = (Holder) PaperweightPlatformAdapter.PALETTED_CONTAINER_GET.invoke(i); + } + } catch (Throwable e) { + throw new RuntimeException(e); + } } } else { LOGGER.error( diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java index 23f59e8bf..a56548c46 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java @@ -123,6 +123,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static Field LEVEL_CHUNK_ENTITIES; private static Field SERVER_LEVEL_ENTITY_MANAGER; + static final MethodHandle PALETTED_CONTAINER_GET; + static { final MethodHandles.Lookup lookup = MethodHandles.lookup(); try { @@ -212,6 +214,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } catch (NoSuchFieldException ignored) { } POST_CHUNK_REWRITE = chunkRewrite; + + Method palettedContaienrGet = PalettedContainer.class.getDeclaredMethod( + Refraction.pickName("get", "a"), + int.class + ); + palettedContaienrGet.setAccessible(true); + PALETTED_CONTAINER_GET = lookup.unreflect(palettedContaienrGet); } catch (RuntimeException | Error e) { throw e; } catch (Exception e) { diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java index 23c882284..85a8de38b 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java @@ -15,6 +15,7 @@ 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.BlockTypesCache; +import io.papermc.lib.PaperLib; import net.minecraft.core.Holder; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; @@ -179,8 +180,18 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { biomes[layer] = new Holder[64]; } if (biomeData instanceof PalettedContainer> palettedContainer) { - for (int i = 0; i < 64; i++) { - biomes[layer][i] = palettedContainer.get(i); + if (PaperLib.isPaper()) { + for (int i = 0; i < 64; i++) { + biomes[layer][i] = palettedContainer.get(i); // Only public on paper + } + } else { + try { + for (int i = 0; i < 64; i++) { + biomes[layer][i] = (Holder) PaperweightPlatformAdapter.PALETTED_CONTAINER_GET.invoke(i); + } + } catch (Throwable e) { + throw new RuntimeException(e); + } } } else { LOGGER.error( diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java index b69f476d3..76cc25e02 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java @@ -123,6 +123,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static Field LEVEL_CHUNK_ENTITIES; private static Field SERVER_LEVEL_ENTITY_MANAGER; + static final MethodHandle PALETTED_CONTAINER_GET; + static { final MethodHandles.Lookup lookup = MethodHandles.lookup(); try { @@ -212,6 +214,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } catch (NoSuchFieldException ignored) { } POST_CHUNK_REWRITE = chunkRewrite; + + Method palettedContaienrGet = PalettedContainer.class.getDeclaredMethod( + Refraction.pickName("get", "a"), + int.class + ); + palettedContaienrGet.setAccessible(true); + PALETTED_CONTAINER_GET = lookup.unreflect(palettedContaienrGet); } catch (RuntimeException | Error e) { throw e; } catch (Exception e) { diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks_Copy.java index 146760020..bb395cbd3 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks_Copy.java @@ -15,6 +15,7 @@ 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.BlockTypesCache; +import io.papermc.lib.PaperLib; import net.minecraft.core.Holder; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ServerLevel; @@ -180,8 +181,18 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { biomes[layer] = new Holder[64]; } if (biomeData instanceof PalettedContainer> palettedContainer) { - for (int i = 0; i < 64; i++) { - biomes[layer][i] = palettedContainer.get(i); + if (PaperLib.isPaper()) { + for (int i = 0; i < 64; i++) { + biomes[layer][i] = palettedContainer.get(i); // Only public on paper + } + } else { + try { + for (int i = 0; i < 64; i++) { + biomes[layer][i] = (Holder) PaperweightPlatformAdapter.PALETTED_CONTAINER_GET.invoke(i); + } + } catch (Throwable e) { + throw new RuntimeException(e); + } } } else { LOGGER.error( diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java index 03eabc698..df71dae8c 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java @@ -121,6 +121,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static Field LEVEL_CHUNK_ENTITIES; private static Field SERVER_LEVEL_ENTITY_MANAGER; + static final MethodHandle PALETTED_CONTAINER_GET; + static { final MethodHandles.Lookup lookup = MethodHandles.lookup(); try { @@ -210,6 +212,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } catch (NoSuchFieldException ignored) { } POST_CHUNK_REWRITE = chunkRewrite; + + Method palettedContaienrGet = PalettedContainer.class.getDeclaredMethod( + Refraction.pickName("get", "a"), + int.class + ); + palettedContaienrGet.setAccessible(true); + PALETTED_CONTAINER_GET = lookup.unreflect(palettedContaienrGet); } catch (RuntimeException | Error e) { throw e; } catch (Exception e) { diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks_Copy.java index a0a4d02d9..1f42361c3 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks_Copy.java @@ -15,6 +15,7 @@ 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.BlockTypesCache; +import io.papermc.lib.PaperLib; import net.minecraft.core.Holder; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ServerLevel; @@ -180,8 +181,18 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { biomes[layer] = new Holder[64]; } if (biomeData instanceof PalettedContainer> palettedContainer) { - for (int i = 0; i < 64; i++) { - biomes[layer][i] = palettedContainer.get(i); + if (PaperLib.isPaper()) { + for (int i = 0; i < 64; i++) { + biomes[layer][i] = palettedContainer.get(i); // Only public on paper + } + } else { + try { + for (int i = 0; i < 64; i++) { + biomes[layer][i] = (Holder) PaperweightPlatformAdapter.PALETTED_CONTAINER_GET.invoke(i); + } + } catch (Throwable e) { + throw new RuntimeException(e); + } } } else { LOGGER.error( diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java index ab55c7814..b4ed7c8ae 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java @@ -119,6 +119,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static Method PAPER_CHUNK_GEN_ALL_ENTITIES; private static Field SERVER_LEVEL_ENTITY_MANAGER; + static final MethodHandle PALETTED_CONTAINER_GET; + static { final MethodHandles.Lookup lookup = MethodHandles.lookup(); try { @@ -195,6 +197,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "N")); SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true); } + + Method palettedContaienrGet = PalettedContainer.class.getDeclaredMethod( + Refraction.pickName("get", "a"), + int.class + ); + palettedContaienrGet.setAccessible(true); + PALETTED_CONTAINER_GET = lookup.unreflect(palettedContaienrGet); } catch (RuntimeException | Error e) { throw e; } catch (Exception e) { From 1e8778b528a58707b685739f64e01cac50d0a5ac Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sat, 14 Sep 2024 10:47:37 +0200 Subject: [PATCH 375/466] Avoid deprecated CompoundTag in API (#2883) * Avoid deprecated CompoundTag in API * use javax annotations --- .../v1_20_R2/PaperweightBlockMaterial.java | 12 +- .../fawe/v1_20_R2/PaperweightFaweAdapter.java | 8 ++ .../fawe/v1_20_R2/PaperweightGetBlocks.java | 102 ++++++------- .../v1_20_R2/PaperweightGetBlocks_Copy.java | 53 +++---- .../v1_20_R3/PaperweightBlockMaterial.java | 12 +- .../fawe/v1_20_R3/PaperweightFaweAdapter.java | 8 ++ .../fawe/v1_20_R3/PaperweightGetBlocks.java | 101 ++++++------- .../v1_20_R3/PaperweightGetBlocks_Copy.java | 53 +++---- .../v1_20_R4/PaperweightBlockMaterial.java | 17 ++- .../fawe/v1_20_R4/PaperweightFaweAdapter.java | 8 ++ .../fawe/v1_20_R4/PaperweightGetBlocks.java | 101 ++++++------- .../v1_20_R4/PaperweightGetBlocks_Copy.java | 55 +++---- .../v1_21_R1/PaperweightBlockMaterial.java | 17 ++- .../fawe/v1_21_R1/PaperweightFaweAdapter.java | 8 ++ .../fawe/v1_21_R1/PaperweightGetBlocks.java | 104 +++++++------- .../v1_21_R1/PaperweightGetBlocks_Copy.java | 55 +++---- .../sk89q/worldedit/bukkit/BukkitWorld.java | 4 +- .../bukkit/adapter/BukkitImplLoader.java | 4 +- .../cli/schematic/ClipboardWorld.java | 4 +- .../core/extent/HistoryExtent.java | 8 +- .../clipboard/CPUOptimizedClipboard.java | 8 ++ .../clipboard/DiskOptimizedClipboard.java | 15 +- .../core/extent/clipboard/EmptyClipboard.java | 5 +- .../clipboard/MemoryOptimizedClipboard.java | 8 ++ .../extent/clipboard/ReadOnlyClipboard.java | 4 +- .../clipboard/io/FastSchematicReaderV3.java | 6 +- .../extent/filter/block/ArrayFilterBlock.java | 6 + .../extent/filter/block/CharFilterBlock.java | 34 +++-- .../core/extent/filter/block/FilterBlock.java | 17 +-- .../history/changeset/AbstractChangeSet.java | 127 ++++++++++++----- .../changeset/AbstractDelegateChangeSet.java | 42 +++--- .../history/changeset/BlockBagChangeSet.java | 11 -- .../changeset/FaweStreamChangeSet.java | 40 +++--- .../core/history/changeset/NullChangeSet.java | 10 +- .../core/nbt/EagerFaweCompoundTag.java | 7 + .../core/nbt/FaweCompoundTag.java | 44 ++++++ .../core/nbt/LazyFaweCompoundTag.java | 14 ++ .../core/queue/IBlocks.java | 38 ++++- .../core/queue/IChunkExtent.java | 36 ++--- .../core/queue/IChunkGet.java | 22 ++- .../core/queue/IChunkSet.java | 16 ++- .../core/queue/ITileInput.java | 1 + .../implementation/blocks/BitSetBlocks.java | 15 +- .../implementation/blocks/CharGetBlocks.java | 3 +- .../implementation/blocks/CharSetBlocks.java | 20 +-- .../implementation/blocks/NullChunkGet.java | 28 ++-- .../blocks/ThreadUnsafeCharBlocks.java | 25 ++-- .../implementation/chunk/ChunkHolder.java | 57 ++++---- .../queue/implementation/chunk/NullChunk.java | 52 +++---- .../core/util/MainUtil.java | 5 + .../core/util/NbtUtils.java | 134 +++++++++++++++++- .../core/world/block/CompoundInput.java | 14 ++ .../core/wrappers/WorldWrapper.java | 5 +- .../main/java/com/sk89q/jnbt/NBTUtils.java | 2 + .../extent/AbstractDelegateExtent.java | 5 +- .../com/sk89q/worldedit/extent/Extent.java | 1 - .../sk89q/worldedit/extent/NullExtent.java | 4 +- .../sk89q/worldedit/extent/OutputExtent.java | 20 ++- .../extent/clipboard/BlockArrayClipboard.java | 8 +- .../sk89q/worldedit/math/BlockVector3.java | 1 + .../session/request/RequestExtent.java | 6 +- .../com/sk89q/worldedit/world/NullWorld.java | 4 +- .../worldedit/world/block/BaseBlock.java | 9 +- .../worldedit/world/block/BlockState.java | 7 + .../world/block/BlockStateHolder.java | 5 + .../world/registry/BlockMaterial.java | 15 +- .../registry/PassthroughBlockMaterial.java | 7 + .../world/registry/SimpleBlockMaterial.java | 11 +- 68 files changed, 1096 insertions(+), 612 deletions(-) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/nbt/EagerFaweCompoundTag.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/nbt/FaweCompoundTag.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/nbt/LazyFaweCompoundTag.java diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightBlockMaterial.java index a50489b93..1ecdb4116 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightBlockMaterial.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightBlockMaterial.java @@ -1,10 +1,8 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.util.ReflectionUtil; import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.world.registry.BlockMaterial; import net.minecraft.core.BlockPos; import net.minecraft.world.level.EmptyBlockGetter; @@ -17,6 +15,8 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.PushReaction; import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData; +import javax.annotation.Nullable; + public class PaperweightBlockMaterial implements BlockMaterial { private final Block block; @@ -25,7 +25,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { private final CraftBlockData craftBlockData; private final org.bukkit.Material craftMaterial; private final int opacity; - private final CompoundTag tile; + private final FaweCompoundTag tile; public PaperweightBlockMaterial(Block block) { this(block, block.defaultBlockState()); @@ -48,7 +48,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { ); tile = tileEntity == null ? null - : new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); + : PaperweightGetBlocks.NMS_TO_TILE.apply(tileEntity); } public Block getBlock() { @@ -173,7 +173,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { } @Override - public CompoundTag getDefaultTile() { + public @Nullable FaweCompoundTag defaultTile() { return tile; } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java index 53f8ef671..bb2d506f5 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java @@ -5,6 +5,7 @@ import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; @@ -97,6 +98,7 @@ import java.util.Map; import java.util.Objects; import java.util.OptionalInt; import java.util.Set; +import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -129,6 +131,12 @@ public final class PaperweightFaweAdapter extends FaweAdapter blockEntityToCompoundTag() { + return blockEntity -> FaweCompoundTag.of( + () -> (LinCompoundTag) toNativeLin(blockEntity.saveWithId()) + ); + } + @Nullable private static String getEntityId(Entity entity) { ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType()); diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java index 93f84a1ec..4bcdee27d 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java @@ -7,20 +7,16 @@ import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.implementation.QueueHandler; import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; import com.fastasyncworldedit.core.util.MathMan; +import com.fastasyncworldedit.core.util.NbtUtils; import com.fastasyncworldedit.core.util.collection.AdaptedMap; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; @@ -34,6 +30,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.IdMap; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; +import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.IntTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; @@ -61,11 +58,19 @@ import org.bukkit.World; import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTagType; import javax.annotation.Nonnull; -import java.util.AbstractSet; +import javax.annotation.Nullable; +import java.util.AbstractCollection; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -82,7 +87,6 @@ import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Function; -import java.util.stream.Collectors; import static net.minecraft.core.registries.Registries.BIOME; @@ -91,8 +95,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Function posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); - private static final Function nmsTile2We = - tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); + public static final Function NMS_TO_TILE = ((PaperweightFaweAdapter) WorldEditPlugin + .getInstance() + .getBukkitImplAdapter()).blockEntityToCompoundTag(); private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin .getInstance() .getBukkitImplAdapter()); @@ -256,23 +261,24 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public CompoundTag getTile(int x, int y, int z) { + public FaweCompoundTag tile(final int x, final int y, final int z) { BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( chunkX << 4), y, (z & 15) + ( chunkZ << 4))); if (blockEntity == null) { return null; } - return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)); + return NMS_TO_TILE.apply(blockEntity); + } @Override - public Map getTiles() { + public Map tiles() { Map nmsTiles = getChunk().getBlockEntities(); if (nmsTiles.isEmpty()) { return Collections.emptyMap(); } - return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); + return AdaptedMap.immutable(nmsTiles, posNms2We, NMS_TO_TILE); } @Override @@ -335,7 +341,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public CompoundTag getEntity(UUID uuid) { + public @Nullable FaweCompoundTag entity(final UUID uuid) { ensureLoaded(serverLevel, chunkX, chunkZ); List entities = PaperweightPlatformAdapter.getEntities(getChunk()); Entity entity = null; @@ -347,10 +353,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (entity != null) { org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); - return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); + return FaweCompoundTag.of(BukkitAdapter.adapt(bukkitEnt).getState().getNbt()); } - for (CompoundTag tag : getEntities()) { - if (uuid.equals(tag.getUUID())) { + for (FaweCompoundTag tag : entities()) { + if (uuid.equals(NbtUtils.uuid(tag))) { return tag; } } @@ -358,14 +364,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public Set getEntities() { + public Collection entities() { ensureLoaded(serverLevel, chunkX, chunkZ); List entities = PaperweightPlatformAdapter.getEntities(getChunk()); if (entities.isEmpty()) { - return Collections.emptySet(); + return Collections.emptyList(); } int size = entities.size(); - return new AbstractSet<>() { + return new AbstractCollection<>() { @Override public int size() { return size; @@ -378,10 +384,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public boolean contains(Object get) { - if (!(get instanceof CompoundTag getTag)) { + if (!(get instanceof FaweCompoundTag getTag)) { return false; } - UUID getUUID = getTag.getUUID(); + UUID getUUID = NbtUtils.uuid(getTag); for (Entity entity : entities) { UUID uuid = entity.getUUID(); if (uuid.equals(getUUID)) { @@ -393,12 +399,12 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Nonnull @Override - public Iterator iterator() { - Iterable result = entities.stream().map(input -> { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + public Iterator iterator() { + Iterable result = entities.stream().map(input -> { + CompoundTag tag = new CompoundTag(); input.save(tag); - return (CompoundTag) adapter.toNative(tag); - }).collect(Collectors.toList()); + return FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(tag)); + })::iterator; return result.iterator(); } }; @@ -728,43 +734,42 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc }; } - Set entities = set.getEntities(); + Collection entities = set.entities(); if (entities != null && !entities.isEmpty()) { if (syncTasks == null) { syncTasks = new Runnable[2]; } syncTasks[1] = () -> { - Iterator iterator = entities.iterator(); + Iterator iterator = entities.iterator(); while (iterator.hasNext()) { - final CompoundTag nativeTag = iterator.next(); - final Map> entityTagMap = nativeTag.getValue(); - final StringTag idTag = (StringTag) entityTagMap.get("Id"); - final ListTag posTag = (ListTag) entityTagMap.get("Pos"); - final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); + final FaweCompoundTag nativeTag = iterator.next(); + final LinCompoundTag linTag = nativeTag.linTag(); + final LinStringTag idTag = linTag.findTag("Id", LinTagType.stringTag()); + final LinListTag posTag = linTag.findListTag("Pos", LinTagType.doubleTag()); + final LinListTag rotTag = linTag.findListTag("Rotation", LinTagType.floatTag()); if (idTag == null || posTag == null || rotTag == null) { LOGGER.error("Unknown entity tag: {}", nativeTag); continue; } - final double x = posTag.getDouble(0); - final double y = posTag.getDouble(1); - final double z = posTag.getDouble(2); - final float yaw = rotTag.getFloat(0); - final float pitch = rotTag.getFloat(1); - final String id = idTag.getValue(); + final double x = posTag.get(0).valueAsDouble(); + final double y = posTag.get(1).valueAsDouble(); + final double z = posTag.get(2).valueAsDouble(); + final float yaw = rotTag.get(0).valueAsFloat(); + final float pitch = rotTag.get(1).valueAsFloat(); + final String id = idTag.value(); EntityType type = EntityType.byString(id).orElse(null); if (type != null) { Entity entity = type.create(nmsWorld); if (entity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); + final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(linTag); for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { tag.remove(name); } entity.load(tag); entity.absMoveTo(x, y, z, yaw, pitch); - entity.setUUID(nativeTag.getUUID()); + entity.setUUID(NbtUtils.uuid(nativeTag)); if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { LOGGER.warn( "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", @@ -784,15 +789,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } // set tiles - Map tiles = set.getTiles(); + Map tiles = set.tiles(); if (tiles != null && !tiles.isEmpty()) { if (syncTasks == null) { syncTasks = new Runnable[1]; } syncTasks[0] = () -> { - for (final Map.Entry entry : tiles.entrySet()) { - final CompoundTag nativeTag = entry.getValue(); + for (final Map.Entry entry : tiles.entrySet()) { + final FaweCompoundTag nativeTag = entry.getValue(); final BlockVector3 blockHash = entry.getKey(); final int x = blockHash.x() + bx; final int y = blockHash.y(); @@ -806,8 +811,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc tileEntity = nmsWorld.getBlockEntity(pos); } if (tileEntity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); + final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag()); tag.put("x", IntTag.valueOf(x)); tag.put("y", IntTag.valueOf(y)); tag.put("z", IntTag.valueOf(z)); diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java index 26a551f2a..e655dd206 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks_Copy.java @@ -1,14 +1,13 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBlocks; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; +import com.fastasyncworldedit.core.util.NbtUtils; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; @@ -17,6 +16,7 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypesCache; import io.papermc.lib.PaperLib; import net.minecraft.core.Holder; +import net.minecraft.nbt.Tag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.biome.Biome; @@ -25,9 +25,11 @@ import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerRO; import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -39,8 +41,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { private static final Logger LOGGER = LogManagerCompat.getLogger(); - private final Map tiles = new HashMap<>(); - private final Set entities = new HashSet<>(); + private final Map tiles = new HashMap<>(); + private final Set entities = new HashSet<>(); private final char[][] blocks; private final int minHeight; private final int maxHeight; @@ -57,44 +59,35 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { } protected void storeTile(BlockEntity blockEntity) { + @SuppressWarnings("unchecked") + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); tiles.put( BlockVector3.at( blockEntity.getBlockPos().getX(), blockEntity.getBlockPos().getY(), blockEntity.getBlockPos().getZ() ), - new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)) + FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(blockEntity.saveWithId())) ); } - @Override - public Map getTiles() { - return tiles; - } - - @Override - @Nullable - public CompoundTag getTile(int x, int y, int z) { - return tiles.get(BlockVector3.at(x, y, z)); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) protected void storeEntity(Entity entity) { - BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + @SuppressWarnings("unchecked") + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); entity.save(compoundTag); - entities.add((CompoundTag) adapter.toNative(compoundTag)); + entities.add(FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(compoundTag))); } @Override - public Set getEntities() { + public Collection entities() { return this.entities; } @Override - public CompoundTag getEntity(UUID uuid) { - for (CompoundTag tag : entities) { - if (uuid.equals(tag.getUUID())) { + public @Nullable FaweCompoundTag entity(final UUID uuid) { + for (FaweCompoundTag tag : entities) { + if (uuid.equals(NbtUtils.uuid(tag))) { return tag; } } @@ -205,7 +198,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { @Override public BaseBlock getFullBlock(int x, int y, int z) { BlockState state = BlockTypesCache.states[get(x, y, z)]; - return state.toBaseBlock(this, x, y, z); + return state.toBaseBlock((IBlocks) this, x, y, z); } @Override @@ -235,6 +228,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { return BlockTypesCache.states[get(x, y, z)]; } + @Override + public Map tiles() { + return tiles; + } + + @Override + public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) { + return tiles.get(BlockVector3.at(x, y, z)); + } + @Override public int getSkyLight(int x, int y, int z) { return 0; diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java index 857d09aa6..d4082eb70 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java @@ -1,8 +1,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt.PaperweightLazyCompoundTag; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.worldedit.world.registry.BlockMaterial; import net.minecraft.core.BlockPos; import net.minecraft.world.level.EmptyBlockGetter; @@ -14,6 +12,8 @@ import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.material.PushReaction; import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; +import javax.annotation.Nullable; + public class PaperweightBlockMaterial implements BlockMaterial { private final Block block; @@ -21,7 +21,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { private final CraftBlockData craftBlockData; private final org.bukkit.Material craftMaterial; private final int opacity; - private final CompoundTag tile; + private final FaweCompoundTag tile; public PaperweightBlockMaterial(Block block) { this(block, block.defaultBlockState()); @@ -39,7 +39,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { ); tile = tileEntity == null ? null - : new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); + : PaperweightGetBlocks.NMS_TO_TILE.apply(tileEntity); } public Block getBlock() { @@ -163,7 +163,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { } @Override - public CompoundTag getDefaultTile() { + public @Nullable FaweCompoundTag defaultTile() { return tile; } diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java index 30ef3423a..c4af78e95 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java @@ -5,6 +5,7 @@ import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; @@ -97,6 +98,7 @@ import java.util.Map; import java.util.Objects; import java.util.OptionalInt; import java.util.Set; +import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -129,6 +131,12 @@ public final class PaperweightFaweAdapter extends FaweAdapter blockEntityToCompoundTag() { + return blockEntity -> FaweCompoundTag.of( + () -> (LinCompoundTag) toNativeLin(blockEntity.saveWithId()) + ); + } + @Nullable private static String getEntityId(Entity entity) { ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType()); diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java index d2d18968a..8bce9c398 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java @@ -7,20 +7,16 @@ import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.implementation.QueueHandler; import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; import com.fastasyncworldedit.core.util.MathMan; +import com.fastasyncworldedit.core.util.NbtUtils; import com.fastasyncworldedit.core.util.collection.AdaptedMap; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; @@ -34,6 +30,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.IdMap; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; +import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.IntTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; @@ -61,11 +58,19 @@ import org.bukkit.World; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTagType; import javax.annotation.Nonnull; -import java.util.AbstractSet; +import javax.annotation.Nullable; +import java.util.AbstractCollection; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -82,7 +87,6 @@ import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Function; -import java.util.stream.Collectors; import static net.minecraft.core.registries.Registries.BIOME; @@ -91,8 +95,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Function posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); - private static final Function nmsTile2We = - tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); + public static final Function NMS_TO_TILE = ((PaperweightFaweAdapter) WorldEditPlugin + .getInstance() + .getBukkitImplAdapter()).blockEntityToCompoundTag(); private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin .getInstance() .getBukkitImplAdapter()); @@ -108,6 +113,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private final Registry biomeRegistry; private final IdMap> biomeHolderIdMap; private final ConcurrentHashMap copies = new ConcurrentHashMap<>(); + private final Object sendLock = new Object(); private LevelChunkSection[] sections; private LevelChunk levelChunk; private DataLayer[] blockLight; @@ -255,23 +261,24 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public CompoundTag getTile(int x, int y, int z) { + public FaweCompoundTag tile(final int x, final int y, final int z) { BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( chunkX << 4), y, (z & 15) + ( chunkZ << 4))); if (blockEntity == null) { return null; } - return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)); + return NMS_TO_TILE.apply(blockEntity); + } @Override - public Map getTiles() { + public Map tiles() { Map nmsTiles = getChunk().getBlockEntities(); if (nmsTiles.isEmpty()) { return Collections.emptyMap(); } - return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); + return AdaptedMap.immutable(nmsTiles, posNms2We, NMS_TO_TILE); } @Override @@ -334,7 +341,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public CompoundTag getEntity(UUID uuid) { + public @Nullable FaweCompoundTag entity(final UUID uuid) { ensureLoaded(serverLevel, chunkX, chunkZ); List entities = PaperweightPlatformAdapter.getEntities(getChunk()); Entity entity = null; @@ -346,10 +353,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (entity != null) { org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); - return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); + return FaweCompoundTag.of(BukkitAdapter.adapt(bukkitEnt).getState().getNbt()); } - for (CompoundTag tag : getEntities()) { - if (uuid.equals(tag.getUUID())) { + for (FaweCompoundTag tag : entities()) { + if (uuid.equals(NbtUtils.uuid(tag))) { return tag; } } @@ -357,14 +364,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public Set getEntities() { + public Collection entities() { ensureLoaded(serverLevel, chunkX, chunkZ); List entities = PaperweightPlatformAdapter.getEntities(getChunk()); if (entities.isEmpty()) { - return Collections.emptySet(); + return Collections.emptyList(); } int size = entities.size(); - return new AbstractSet<>() { + return new AbstractCollection<>() { @Override public int size() { return size; @@ -377,10 +384,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public boolean contains(Object get) { - if (!(get instanceof CompoundTag getTag)) { + if (!(get instanceof FaweCompoundTag getTag)) { return false; } - UUID getUUID = getTag.getUUID(); + UUID getUUID = NbtUtils.uuid(getTag); for (Entity entity : entities) { UUID uuid = entity.getUUID(); if (uuid.equals(getUUID)) { @@ -392,12 +399,12 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Nonnull @Override - public Iterator iterator() { - Iterable result = entities.stream().map(input -> { + public Iterator iterator() { + Iterable result = entities.stream().map(input -> { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); input.save(tag); - return (CompoundTag) adapter.toNative(tag); - }).collect(Collectors.toList()); + return FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(tag)); + })::iterator; return result.iterator(); } }; @@ -727,43 +734,42 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc }; } - Set entities = set.getEntities(); + Collection entities = set.entities(); if (entities != null && !entities.isEmpty()) { if (syncTasks == null) { syncTasks = new Runnable[2]; } syncTasks[1] = () -> { - Iterator iterator = entities.iterator(); + Iterator iterator = entities.iterator(); while (iterator.hasNext()) { - final CompoundTag nativeTag = iterator.next(); - final Map> entityTagMap = nativeTag.getValue(); - final StringTag idTag = (StringTag) entityTagMap.get("Id"); - final ListTag posTag = (ListTag) entityTagMap.get("Pos"); - final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); + final FaweCompoundTag nativeTag = iterator.next(); + final LinCompoundTag linTag = nativeTag.linTag(); + final LinStringTag idTag = linTag.findTag("Id", LinTagType.stringTag()); + final LinListTag posTag = linTag.findListTag("Pos", LinTagType.doubleTag()); + final LinListTag rotTag = linTag.findListTag("Rotation", LinTagType.floatTag()); if (idTag == null || posTag == null || rotTag == null) { LOGGER.error("Unknown entity tag: {}", nativeTag); continue; } - final double x = posTag.getDouble(0); - final double y = posTag.getDouble(1); - final double z = posTag.getDouble(2); - final float yaw = rotTag.getFloat(0); - final float pitch = rotTag.getFloat(1); - final String id = idTag.getValue(); + final double x = posTag.get(0).valueAsDouble(); + final double y = posTag.get(1).valueAsDouble(); + final double z = posTag.get(2).valueAsDouble(); + final float yaw = rotTag.get(0).valueAsFloat(); + final float pitch = rotTag.get(1).valueAsFloat(); + final String id = idTag.value(); EntityType type = EntityType.byString(id).orElse(null); if (type != null) { Entity entity = type.create(nmsWorld); if (entity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); + final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(linTag); for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { tag.remove(name); } entity.load(tag); entity.absMoveTo(x, y, z, yaw, pitch); - entity.setUUID(nativeTag.getUUID()); + entity.setUUID(NbtUtils.uuid(nativeTag)); if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { LOGGER.warn( "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", @@ -783,15 +789,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } // set tiles - Map tiles = set.getTiles(); + Map tiles = set.tiles(); if (tiles != null && !tiles.isEmpty()) { if (syncTasks == null) { syncTasks = new Runnable[1]; } syncTasks[0] = () -> { - for (final Map.Entry entry : tiles.entrySet()) { - final CompoundTag nativeTag = entry.getValue(); + for (final Map.Entry entry : tiles.entrySet()) { + final FaweCompoundTag nativeTag = entry.getValue(); final BlockVector3 blockHash = entry.getKey(); final int x = blockHash.x() + bx; final int y = blockHash.y(); @@ -805,8 +811,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc tileEntity = nmsWorld.getBlockEntity(pos); } if (tileEntity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); + final net.minecraft.nbt.CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag()); tag.put("x", IntTag.valueOf(x)); tag.put("y", IntTag.valueOf(y)); tag.put("z", IntTag.valueOf(z)); diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java index 85a8de38b..1163c2d33 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java @@ -1,14 +1,13 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBlocks; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; +import com.fastasyncworldedit.core.util.NbtUtils; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; @@ -17,6 +16,7 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypesCache; import io.papermc.lib.PaperLib; import net.minecraft.core.Holder; +import net.minecraft.nbt.Tag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.biome.Biome; @@ -25,9 +25,11 @@ import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerRO; import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -39,8 +41,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { private static final Logger LOGGER = LogManagerCompat.getLogger(); - private final Map tiles = new HashMap<>(); - private final Set entities = new HashSet<>(); + private final Map tiles = new HashMap<>(); + private final Set entities = new HashSet<>(); private final char[][] blocks; private final int minHeight; private final int maxHeight; @@ -57,44 +59,35 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { } protected void storeTile(BlockEntity blockEntity) { + @SuppressWarnings("unchecked") + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); tiles.put( BlockVector3.at( blockEntity.getBlockPos().getX(), blockEntity.getBlockPos().getY(), blockEntity.getBlockPos().getZ() ), - new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)) + FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(blockEntity.saveWithId())) ); } - @Override - public Map getTiles() { - return tiles; - } - - @Override - @Nullable - public CompoundTag getTile(int x, int y, int z) { - return tiles.get(BlockVector3.at(x, y, z)); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) protected void storeEntity(Entity entity) { - BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + @SuppressWarnings("unchecked") + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); entity.save(compoundTag); - entities.add((CompoundTag) adapter.toNative(compoundTag)); + entities.add(FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(compoundTag))); } @Override - public Set getEntities() { + public Collection entities() { return this.entities; } @Override - public CompoundTag getEntity(UUID uuid) { - for (CompoundTag tag : entities) { - if (uuid.equals(tag.getUUID())) { + public @Nullable FaweCompoundTag entity(final UUID uuid) { + for (FaweCompoundTag tag : entities) { + if (uuid.equals(NbtUtils.uuid(tag))) { return tag; } } @@ -205,7 +198,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { @Override public BaseBlock getFullBlock(int x, int y, int z) { BlockState state = BlockTypesCache.states[get(x, y, z)]; - return state.toBaseBlock(this, x, y, z); + return state.toBaseBlock((IBlocks) this, x, y, z); } @Override @@ -235,6 +228,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { return BlockTypesCache.states[get(x, y, z)]; } + @Override + public Map tiles() { + return tiles; + } + + @Override + public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) { + return tiles.get(BlockVector3.at(x, y, z)); + } + @Override public int getSkyLight(int x, int y, int z) { return 0; diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightBlockMaterial.java index e80ecf3cb..15f3abbaf 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightBlockMaterial.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightBlockMaterial.java @@ -1,11 +1,8 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.nbt.PaperweightLazyCompoundTag; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.worldedit.world.registry.BlockMaterial; import net.minecraft.core.BlockPos; -import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.world.level.EmptyBlockGetter; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock; @@ -15,6 +12,8 @@ import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.material.PushReaction; import org.bukkit.craftbukkit.block.data.CraftBlockData; +import javax.annotation.Nullable; + public class PaperweightBlockMaterial implements BlockMaterial { private final Block block; @@ -22,7 +21,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { private final CraftBlockData craftBlockData; private final org.bukkit.Material craftMaterial; private final int opacity; - private final CompoundTag tile; + private final FaweCompoundTag tile; public PaperweightBlockMaterial(Block block) { this(block, block.defaultBlockState()); @@ -38,9 +37,9 @@ public class PaperweightBlockMaterial implements BlockMaterial { BlockPos.ZERO, blockState ); - tile = tileEntity == null ? null : new PaperweightLazyCompoundTag( - Suppliers.memoize(() -> tileEntity.saveWithId(DedicatedServer.getServer().registryAccess())) - ); + tile = tileEntity == null + ? null + : PaperweightGetBlocks.NMS_TO_TILE.apply(tileEntity); } public Block getBlock() { @@ -164,7 +163,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { } @Override - public CompoundTag getDefaultTile() { + public @Nullable FaweCompoundTag defaultTile() { return tile; } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java index 76dc6f951..151ffd1f3 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java @@ -5,6 +5,7 @@ import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; @@ -103,6 +104,7 @@ import java.util.Map; import java.util.Objects; import java.util.OptionalInt; import java.util.Set; +import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -138,6 +140,12 @@ public final class PaperweightFaweAdapter extends FaweAdapter blockEntityToCompoundTag() { + return blockEntity -> FaweCompoundTag.of( + () -> (LinCompoundTag) toNativeLin(blockEntity.saveWithId(DedicatedServer.getServer().registryAccess())) + ); + } + @Nullable private static String getEntityId(Entity entity) { ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType()); diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks.java index 47466ac5e..754b0ab0b 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks.java @@ -7,20 +7,16 @@ import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.implementation.QueueHandler; import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; import com.fastasyncworldedit.core.util.MathMan; +import com.fastasyncworldedit.core.util.NbtUtils; import com.fastasyncworldedit.core.util.collection.AdaptedMap; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; @@ -34,6 +30,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.IdMap; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; +import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.IntTag; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ServerLevel; @@ -62,11 +59,19 @@ import org.bukkit.World; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTagType; import javax.annotation.Nonnull; -import java.util.AbstractSet; +import javax.annotation.Nullable; +import java.util.AbstractCollection; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -83,7 +88,6 @@ import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Function; -import java.util.stream.Collectors; import static net.minecraft.core.registries.Registries.BIOME; @@ -92,9 +96,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Function posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); - private static final Function nmsTile2We = tileEntity -> new PaperweightLazyCompoundTag( - Suppliers.memoize(() -> tileEntity.saveWithId(DedicatedServer.getServer().registryAccess())) - ); + public static final Function NMS_TO_TILE = ((PaperweightFaweAdapter) WorldEditPlugin + .getInstance() + .getBukkitImplAdapter()).blockEntityToCompoundTag(); private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin .getInstance() .getBukkitImplAdapter()); @@ -258,23 +262,24 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public CompoundTag getTile(int x, int y, int z) { + public FaweCompoundTag tile(final int x, final int y, final int z) { BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( chunkX << 4), y, (z & 15) + ( chunkZ << 4))); if (blockEntity == null) { return null; } - return new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()))); + return NMS_TO_TILE.apply(blockEntity); + } @Override - public Map getTiles() { + public Map tiles() { Map nmsTiles = getChunk().getBlockEntities(); if (nmsTiles.isEmpty()) { return Collections.emptyMap(); } - return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); + return AdaptedMap.immutable(nmsTiles, posNms2We, NMS_TO_TILE); } @Override @@ -337,7 +342,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public CompoundTag getEntity(UUID uuid) { + public @Nullable FaweCompoundTag entity(final UUID uuid) { ensureLoaded(serverLevel, chunkX, chunkZ); List entities = PaperweightPlatformAdapter.getEntities(getChunk()); Entity entity = null; @@ -349,10 +354,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (entity != null) { org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); - return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); + return FaweCompoundTag.of(BukkitAdapter.adapt(bukkitEnt).getState().getNbt()); } - for (CompoundTag tag : getEntities()) { - if (uuid.equals(tag.getUUID())) { + for (FaweCompoundTag tag : entities()) { + if (uuid.equals(NbtUtils.uuid(tag))) { return tag; } } @@ -360,14 +365,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public Set getEntities() { + public Collection entities() { ensureLoaded(serverLevel, chunkX, chunkZ); List entities = PaperweightPlatformAdapter.getEntities(getChunk()); if (entities.isEmpty()) { - return Collections.emptySet(); + return Collections.emptyList(); } int size = entities.size(); - return new AbstractSet<>() { + return new AbstractCollection<>() { @Override public int size() { return size; @@ -380,10 +385,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public boolean contains(Object get) { - if (!(get instanceof CompoundTag getTag)) { + if (!(get instanceof FaweCompoundTag getTag)) { return false; } - UUID getUUID = getTag.getUUID(); + UUID getUUID = NbtUtils.uuid(getTag); for (Entity entity : entities) { UUID uuid = entity.getUUID(); if (uuid.equals(getUUID)) { @@ -395,12 +400,12 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Nonnull @Override - public Iterator iterator() { - Iterable result = entities.stream().map(input -> { + public Iterator iterator() { + Iterable result = entities.stream().map(input -> { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); input.save(tag); - return (CompoundTag) adapter.toNative(tag); - }).collect(Collectors.toList()); + return FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(tag)); + })::iterator; return result.iterator(); } }; @@ -728,43 +733,42 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc }; } - Set entities = set.getEntities(); + Collection entities = set.entities(); if (entities != null && !entities.isEmpty()) { if (syncTasks == null) { syncTasks = new Runnable[2]; } syncTasks[1] = () -> { - Iterator iterator = entities.iterator(); + Iterator iterator = entities.iterator(); while (iterator.hasNext()) { - final CompoundTag nativeTag = iterator.next(); - final Map> entityTagMap = nativeTag.getValue(); - final StringTag idTag = (StringTag) entityTagMap.get("Id"); - final ListTag posTag = (ListTag) entityTagMap.get("Pos"); - final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); + final FaweCompoundTag nativeTag = iterator.next(); + final LinCompoundTag linTag = nativeTag.linTag(); + final LinStringTag idTag = linTag.findTag("Id", LinTagType.stringTag()); + final LinListTag posTag = linTag.findListTag("Pos", LinTagType.doubleTag()); + final LinListTag rotTag = linTag.findListTag("Rotation", LinTagType.floatTag()); if (idTag == null || posTag == null || rotTag == null) { LOGGER.error("Unknown entity tag: {}", nativeTag); continue; } - final double x = posTag.getDouble(0); - final double y = posTag.getDouble(1); - final double z = posTag.getDouble(2); - final float yaw = rotTag.getFloat(0); - final float pitch = rotTag.getFloat(1); - final String id = idTag.getValue(); + final double x = posTag.get(0).valueAsDouble(); + final double y = posTag.get(1).valueAsDouble(); + final double z = posTag.get(2).valueAsDouble(); + final float yaw = rotTag.get(0).valueAsFloat(); + final float pitch = rotTag.get(1).valueAsFloat(); + final String id = idTag.value(); EntityType type = EntityType.byString(id).orElse(null); if (type != null) { Entity entity = type.create(nmsWorld); if (entity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); + final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(linTag); for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { tag.remove(name); } entity.load(tag); entity.absMoveTo(x, y, z, yaw, pitch); - entity.setUUID(nativeTag.getUUID()); + entity.setUUID(NbtUtils.uuid(nativeTag)); if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { LOGGER.warn( "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", @@ -784,15 +788,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } // set tiles - Map tiles = set.getTiles(); + Map tiles = set.tiles(); if (tiles != null && !tiles.isEmpty()) { if (syncTasks == null) { syncTasks = new Runnable[1]; } syncTasks[0] = () -> { - for (final Map.Entry entry : tiles.entrySet()) { - final CompoundTag nativeTag = entry.getValue(); + for (final Map.Entry entry : tiles.entrySet()) { + final FaweCompoundTag nativeTag = entry.getValue(); final BlockVector3 blockHash = entry.getKey(); final int x = blockHash.x() + bx; final int y = blockHash.y(); @@ -806,8 +810,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc tileEntity = nmsWorld.getBlockEntity(pos); } if (tileEntity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); + final net.minecraft.nbt.CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag()); tag.put("x", IntTag.valueOf(x)); tag.put("y", IntTag.valueOf(y)); tag.put("z", IntTag.valueOf(z)); diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks_Copy.java index bb395cbd3..7d199c7f6 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks_Copy.java @@ -1,14 +1,13 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBlocks; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; +import com.fastasyncworldedit.core.util.NbtUtils; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; @@ -17,6 +16,7 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypesCache; import io.papermc.lib.PaperLib; import net.minecraft.core.Holder; +import net.minecraft.nbt.Tag; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; @@ -26,9 +26,11 @@ import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerRO; import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -40,8 +42,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { private static final Logger LOGGER = LogManagerCompat.getLogger(); - private final Map tiles = new HashMap<>(); - private final Set entities = new HashSet<>(); + private final Map tiles = new HashMap<>(); + private final Set entities = new HashSet<>(); private final char[][] blocks; private final int minHeight; private final int maxHeight; @@ -58,44 +60,37 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { } protected void storeTile(BlockEntity blockEntity) { + @SuppressWarnings("unchecked") + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); tiles.put( BlockVector3.at( blockEntity.getBlockPos().getX(), blockEntity.getBlockPos().getY(), blockEntity.getBlockPos().getZ() ), - new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()))) + FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(blockEntity.saveWithId(DedicatedServer + .getServer() + .registryAccess()))) ); } - @Override - public Map getTiles() { - return tiles; - } - - @Override - @Nullable - public CompoundTag getTile(int x, int y, int z) { - return tiles.get(BlockVector3.at(x, y, z)); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) protected void storeEntity(Entity entity) { - BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + @SuppressWarnings("unchecked") + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); entity.save(compoundTag); - entities.add((CompoundTag) adapter.toNative(compoundTag)); + entities.add(FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(compoundTag))); } @Override - public Set getEntities() { + public Collection entities() { return this.entities; } @Override - public CompoundTag getEntity(UUID uuid) { - for (CompoundTag tag : entities) { - if (uuid.equals(tag.getUUID())) { + public @Nullable FaweCompoundTag entity(final UUID uuid) { + for (FaweCompoundTag tag : entities) { + if (uuid.equals(NbtUtils.uuid(tag))) { return tag; } } @@ -206,7 +201,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { @Override public BaseBlock getFullBlock(int x, int y, int z) { BlockState state = BlockTypesCache.states[get(x, y, z)]; - return state.toBaseBlock(this, x, y, z); + return state.toBaseBlock((IBlocks) this, x, y, z); } @Override @@ -236,6 +231,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { return BlockTypesCache.states[get(x, y, z)]; } + @Override + public Map tiles() { + return tiles; + } + + @Override + public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) { + return tiles.get(BlockVector3.at(x, y, z)); + } + @Override public int getSkyLight(int x, int y, int z) { return 0; diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightBlockMaterial.java index 537072538..d48e5fe1d 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightBlockMaterial.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightBlockMaterial.java @@ -1,11 +1,8 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.nbt.PaperweightLazyCompoundTag; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.worldedit.world.registry.BlockMaterial; import net.minecraft.core.BlockPos; -import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.world.level.EmptyBlockGetter; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock; @@ -15,6 +12,8 @@ import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.material.PushReaction; import org.bukkit.craftbukkit.block.data.CraftBlockData; +import javax.annotation.Nullable; + public class PaperweightBlockMaterial implements BlockMaterial { private final Block block; @@ -22,7 +21,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { private final CraftBlockData craftBlockData; private final org.bukkit.Material craftMaterial; private final int opacity; - private final CompoundTag tile; + private final FaweCompoundTag tile; public PaperweightBlockMaterial(Block block) { this(block, block.defaultBlockState()); @@ -38,9 +37,9 @@ public class PaperweightBlockMaterial implements BlockMaterial { BlockPos.ZERO, blockState ); - tile = tileEntity == null ? null : new PaperweightLazyCompoundTag( - Suppliers.memoize(() -> tileEntity.saveWithId(DedicatedServer.getServer().registryAccess())) - ); + tile = tileEntity == null + ? null + : PaperweightGetBlocks.NMS_TO_TILE.apply(tileEntity); } public Block getBlock() { @@ -164,7 +163,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { } @Override - public CompoundTag getDefaultTile() { + public @Nullable FaweCompoundTag defaultTile() { return tile; } diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java index 11577ca9e..9452024c5 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java @@ -5,6 +5,7 @@ import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; @@ -102,6 +103,7 @@ import java.util.Map; import java.util.Objects; import java.util.OptionalInt; import java.util.Set; +import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -137,6 +139,12 @@ public final class PaperweightFaweAdapter extends FaweAdapter blockEntityToCompoundTag() { + return blockEntity -> FaweCompoundTag.of( + () -> (LinCompoundTag) toNativeLin(blockEntity.saveWithId(DedicatedServer.getServer().registryAccess())) + ); + } + @Nullable private static String getEntityId(Entity entity) { ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType()); diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks.java index bdd9d0648..6ef85090f 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks.java @@ -7,20 +7,16 @@ import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.implementation.QueueHandler; import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; import com.fastasyncworldedit.core.util.MathMan; +import com.fastasyncworldedit.core.util.NbtUtils; import com.fastasyncworldedit.core.util.collection.AdaptedMap; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; @@ -34,6 +30,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.IdMap; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; +import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.IntTag; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ServerLevel; @@ -62,11 +59,19 @@ import org.bukkit.World; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTagType; import javax.annotation.Nonnull; -import java.util.AbstractSet; +import javax.annotation.Nullable; +import java.util.AbstractCollection; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -83,7 +88,6 @@ import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Function; -import java.util.stream.Collectors; import static net.minecraft.core.registries.Registries.BIOME; @@ -92,9 +96,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Function posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); - private static final Function nmsTile2We = tileEntity -> new PaperweightLazyCompoundTag( - Suppliers.memoize(() -> tileEntity.saveWithId(DedicatedServer.getServer().registryAccess())) - ); + public static final Function NMS_TO_TILE = ((PaperweightFaweAdapter) WorldEditPlugin + .getInstance() + .getBukkitImplAdapter()).blockEntityToCompoundTag(); private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin .getInstance() .getBukkitImplAdapter()); @@ -258,23 +262,24 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public CompoundTag getTile(int x, int y, int z) { + public FaweCompoundTag tile(final int x, final int y, final int z) { BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( chunkX << 4), y, (z & 15) + ( chunkZ << 4))); if (blockEntity == null) { return null; } - return new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()))); + return NMS_TO_TILE.apply(blockEntity); + } @Override - public Map getTiles() { + public Map tiles() { Map nmsTiles = getChunk().getBlockEntities(); if (nmsTiles.isEmpty()) { return Collections.emptyMap(); } - return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); + return AdaptedMap.immutable(nmsTiles, posNms2We, NMS_TO_TILE); } @Override @@ -337,7 +342,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public CompoundTag getEntity(UUID uuid) { + public @Nullable FaweCompoundTag entity(final UUID uuid) { ensureLoaded(serverLevel, chunkX, chunkZ); List entities = PaperweightPlatformAdapter.getEntities(getChunk()); Entity entity = null; @@ -349,10 +354,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (entity != null) { org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); - return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); + return FaweCompoundTag.of(BukkitAdapter.adapt(bukkitEnt).getState().getNbt()); } - for (CompoundTag tag : getEntities()) { - if (uuid.equals(tag.getUUID())) { + for (FaweCompoundTag tag : entities()) { + if (uuid.equals(NbtUtils.uuid(tag))) { return tag; } } @@ -360,14 +365,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public Set getEntities() { + public Collection entities() { ensureLoaded(serverLevel, chunkX, chunkZ); List entities = PaperweightPlatformAdapter.getEntities(getChunk()); if (entities.isEmpty()) { - return Collections.emptySet(); + return Collections.emptyList(); } int size = entities.size(); - return new AbstractSet<>() { + return new AbstractCollection<>() { @Override public int size() { return size; @@ -380,10 +385,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public boolean contains(Object get) { - if (!(get instanceof CompoundTag getTag)) { + if (!(get instanceof FaweCompoundTag getTag)) { return false; } - UUID getUUID = getTag.getUUID(); + UUID getUUID = NbtUtils.uuid(getTag); for (Entity entity : entities) { UUID uuid = entity.getUUID(); if (uuid.equals(getUUID)) { @@ -395,15 +400,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Nonnull @Override - public Iterator iterator() { - Iterable result = entities.stream().map(input -> { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + public Iterator iterator() { + Iterable result = entities.stream().map(input -> { + CompoundTag tag = new CompoundTag(); input.save(tag); - return (CompoundTag) adapter.toNative(tag); - }).collect(Collectors.toList()); + return FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(tag)); + })::iterator; return result.iterator(); } }; + } private void removeEntity(Entity entity) { @@ -722,43 +728,42 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc }; } - Set entities = set.getEntities(); + Collection entities = set.entities(); if (entities != null && !entities.isEmpty()) { if (syncTasks == null) { syncTasks = new Runnable[2]; } syncTasks[1] = () -> { - Iterator iterator = entities.iterator(); + Iterator iterator = entities.iterator(); while (iterator.hasNext()) { - final CompoundTag nativeTag = iterator.next(); - final Map> entityTagMap = nativeTag.getValue(); - final StringTag idTag = (StringTag) entityTagMap.get("Id"); - final ListTag posTag = (ListTag) entityTagMap.get("Pos"); - final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); + final FaweCompoundTag nativeTag = iterator.next(); + final LinCompoundTag linTag = nativeTag.linTag(); + final LinStringTag idTag = linTag.findTag("Id", LinTagType.stringTag()); + final LinListTag posTag = linTag.findListTag("Pos", LinTagType.doubleTag()); + final LinListTag rotTag = linTag.findListTag("Rotation", LinTagType.floatTag()); if (idTag == null || posTag == null || rotTag == null) { LOGGER.error("Unknown entity tag: {}", nativeTag); continue; } - final double x = posTag.getDouble(0); - final double y = posTag.getDouble(1); - final double z = posTag.getDouble(2); - final float yaw = rotTag.getFloat(0); - final float pitch = rotTag.getFloat(1); - final String id = idTag.getValue(); + final double x = posTag.get(0).valueAsDouble(); + final double y = posTag.get(1).valueAsDouble(); + final double z = posTag.get(2).valueAsDouble(); + final float yaw = rotTag.get(0).valueAsFloat(); + final float pitch = rotTag.get(1).valueAsFloat(); + final String id = idTag.value(); EntityType type = EntityType.byString(id).orElse(null); if (type != null) { Entity entity = type.create(nmsWorld); if (entity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); + final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(linTag); for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { tag.remove(name); } entity.load(tag); entity.absMoveTo(x, y, z, yaw, pitch); - entity.setUUID(nativeTag.getUUID()); + entity.setUUID(NbtUtils.uuid(nativeTag)); if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { LOGGER.warn( "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", @@ -778,15 +783,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } // set tiles - Map tiles = set.getTiles(); + Map tiles = set.tiles(); if (tiles != null && !tiles.isEmpty()) { if (syncTasks == null) { syncTasks = new Runnable[1]; } syncTasks[0] = () -> { - for (final Map.Entry entry : tiles.entrySet()) { - final CompoundTag nativeTag = entry.getValue(); + for (final Map.Entry entry : tiles.entrySet()) { + final FaweCompoundTag nativeTag = entry.getValue(); final BlockVector3 blockHash = entry.getKey(); final int x = blockHash.x() + bx; final int y = blockHash.y(); @@ -800,8 +805,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc tileEntity = nmsWorld.getBlockEntity(pos); } if (tileEntity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); + final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag()); tag.put("x", IntTag.valueOf(x)); tag.put("y", IntTag.valueOf(y)); tag.put("z", IntTag.valueOf(z)); diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks_Copy.java index 1f42361c3..18b557b97 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks_Copy.java @@ -1,14 +1,13 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBlocks; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; +import com.fastasyncworldedit.core.util.NbtUtils; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; @@ -17,6 +16,7 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypesCache; import io.papermc.lib.PaperLib; import net.minecraft.core.Holder; +import net.minecraft.nbt.Tag; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; @@ -26,9 +26,11 @@ import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerRO; import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -40,8 +42,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { private static final Logger LOGGER = LogManagerCompat.getLogger(); - private final Map tiles = new HashMap<>(); - private final Set entities = new HashSet<>(); + private final Map tiles = new HashMap<>(); + private final Set entities = new HashSet<>(); private final char[][] blocks; private final int minHeight; private final int maxHeight; @@ -58,44 +60,37 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { } protected void storeTile(BlockEntity blockEntity) { + @SuppressWarnings("unchecked") + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); tiles.put( BlockVector3.at( blockEntity.getBlockPos().getX(), blockEntity.getBlockPos().getY(), blockEntity.getBlockPos().getZ() ), - new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()))) + FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(blockEntity.saveWithId(DedicatedServer + .getServer() + .registryAccess()))) ); } - @Override - public Map getTiles() { - return tiles; - } - - @Override - @Nullable - public CompoundTag getTile(int x, int y, int z) { - return tiles.get(BlockVector3.at(x, y, z)); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) protected void storeEntity(Entity entity) { - BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + @SuppressWarnings("unchecked") + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); entity.save(compoundTag); - entities.add((CompoundTag) adapter.toNative(compoundTag)); + entities.add(FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(compoundTag))); } @Override - public Set getEntities() { + public Collection entities() { return this.entities; } @Override - public CompoundTag getEntity(UUID uuid) { - for (CompoundTag tag : entities) { - if (uuid.equals(tag.getUUID())) { + public @Nullable FaweCompoundTag entity(final UUID uuid) { + for (FaweCompoundTag tag : entities) { + if (uuid.equals(NbtUtils.uuid(tag))) { return tag; } } @@ -206,7 +201,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { @Override public BaseBlock getFullBlock(int x, int y, int z) { BlockState state = BlockTypesCache.states[get(x, y, z)]; - return state.toBaseBlock(this, x, y, z); + return state.toBaseBlock((IBlocks) this, x, y, z); } @Override @@ -236,6 +231,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { return BlockTypesCache.states[get(x, y, z)]; } + @Override + public Map tiles() { + return tiles; + } + + @Override + public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) { + return tiles.get(BlockVector3.at(x, y, z)); + } + @Override public int getSkyLight(int x, int y, int z) { return 0; 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 66507c151..55912d770 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 @@ -24,12 +24,12 @@ import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.internal.exception.FaweException; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.TaskManager; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; -import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; @@ -665,7 +665,7 @@ public class BukkitWorld extends AbstractWorld { } @Override - public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { + public boolean tile(int x, int y, int z, FaweCompoundTag tile) throws WorldEditException { return false; } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java index 5cf783350..f55029ac4 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java @@ -165,9 +165,11 @@ public class BukkitImplLoader { * @throws AdapterLoadException thrown if no adapter could be found */ public BukkitImplAdapter loadAdapter() throws AdapterLoadException { + // FAWE - do not initialize classes on lookup + final ClassLoader classLoader = this.getClass().getClassLoader(); for (String className : adapterCandidates) { try { - Class cls = Class.forName(className); + Class cls = Class.forName(className, false, classLoader); if (cls.isSynthetic()) { continue; } 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 index e0b4c64f2..1502fdbf3 100644 --- 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 @@ -19,10 +19,10 @@ package com.sk89q.worldedit.cli.schematic; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.google.common.collect.ImmutableSet; -import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEditException; @@ -193,7 +193,7 @@ public class ClipboardWorld extends AbstractWorld implements Clipboard, CLIWorld } @Override - public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { + public boolean tile(int x, int y, int z, FaweCompoundTag tile) throws WorldEditException { return false; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java index daad170da..720b5e57b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java @@ -2,6 +2,7 @@ package com.fastasyncworldedit.core.extent; import com.fastasyncworldedit.core.history.changeset.AbstractChangeSet; import com.fastasyncworldedit.core.math.MutableBlockVector3; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; @@ -74,7 +75,7 @@ public class HistoryExtent extends AbstractDelegateExtent { public Entity createEntity(Location location, BaseEntity state) { final Entity entity = super.createEntity(location, state); if (state != null) { - this.changeSet.addEntityCreate(state.getNbtData()); + this.changeSet.addEntityCreate(FaweCompoundTag.of(state.getNbt())); } return entity; } @@ -84,7 +85,7 @@ public class HistoryExtent extends AbstractDelegateExtent { public Entity createEntity(Location location, BaseEntity state, UUID uuid) { final Entity entity = super.createEntity(location, state, uuid); if (state != null) { - this.changeSet.addEntityCreate(state.getNbtData()); + this.changeSet.addEntityCreate(FaweCompoundTag.of(state.getNbt())); } return entity; } @@ -154,11 +155,10 @@ public class HistoryExtent extends AbstractDelegateExtent { @Override public boolean remove() { - final Location location = this.entity.getLocation(); final BaseEntity state = this.entity.getState(); final boolean success = this.entity.remove(); if (state != null && success) { - HistoryExtent.this.changeSet.addEntityRemove(state.getNbtData()); + HistoryExtent.this.changeSet.addEntityRemove(FaweCompoundTag.of(state.getNbt())); } return success; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java index 77447ac4c..ef7cc0461 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java @@ -2,9 +2,11 @@ package com.fastasyncworldedit.core.extent.clipboard; import com.fastasyncworldedit.core.jnbt.streamer.IntValueReader; import com.fastasyncworldedit.core.math.IntTriple; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.biome.BiomeType; @@ -175,6 +177,12 @@ public class CPUOptimizedClipboard extends LinearClipboard { return true; } + @Override + public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tile) throws WorldEditException { + // TODO replace + return setTile(x, y, z, new CompoundTag(tile.linTag())); + } + private boolean setTile(int index, CompoundTag tag) { final Map> values = new HashMap<>(tag.getValue()); values.remove("x"); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java index dc7193394..c81059ccb 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java @@ -6,15 +6,17 @@ import com.fastasyncworldedit.core.internal.exception.FaweClipboardVersionMismat import com.fastasyncworldedit.core.internal.io.ByteBufferInputStream; import com.fastasyncworldedit.core.jnbt.streamer.IntValueReader; import com.fastasyncworldedit.core.math.IntTriple; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.util.MainUtil; +import com.fastasyncworldedit.core.util.NbtUtils; import com.fastasyncworldedit.core.util.ReflectionUtils; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.DoubleTag; -import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTOutputStream; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.internal.util.LogManagerCompat; @@ -65,6 +67,7 @@ public class DiskOptimizedClipboard extends LinearClipboard { private static final Map LOCK_HOLDER_CACHE = new ConcurrentHashMap<>(); private final HashMap nbtMap; + private final HashMap nbtMap2; private final File file; private final int headerSize; @@ -124,6 +127,7 @@ public class DiskOptimizedClipboard extends LinearClipboard { canHaveBiomes = false; } nbtMap = new HashMap<>(); + nbtMap2 = new HashMap<>(); try { this.file = file; try { @@ -180,6 +184,7 @@ public class DiskOptimizedClipboard extends LinearClipboard { super(readSize(file, versionOverride), BlockVector3.ZERO); headerSize = getHeaderSizeOverrideFromVersion(versionOverride); nbtMap = new HashMap<>(); + nbtMap2 = new HashMap<>(); try { this.file = file; this.braf = new RandomAccessFile(file, "rw"); @@ -709,12 +714,8 @@ public class DiskOptimizedClipboard extends LinearClipboard { } @Override - public boolean setTile(int x, int y, int z, CompoundTag tag) { - final Map> values = new HashMap<>(tag.getValue()); - values.put("x", new IntTag(x)); - values.put("y", new IntTag(y)); - values.put("z", new IntTag(z)); - nbtMap.put(new IntTriple(x, y, z), new CompoundTag(values)); + public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tile) throws WorldEditException { + nbtMap2.put(new IntTriple(x, y, z), NbtUtils.withPosition(tile, x, y, z)); return true; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/EmptyClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/EmptyClipboard.java index 8e18c2c19..983ea79b0 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/EmptyClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/EmptyClipboard.java @@ -1,7 +1,7 @@ package com.fastasyncworldedit.core.extent.clipboard; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; -import com.sk89q.jnbt.CompoundTag; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.clipboard.Clipboard; @@ -84,7 +84,8 @@ public final class EmptyClipboard implements Clipboard { return false; } - public boolean setTile(int x, int y, int z, @Nonnull CompoundTag tile) throws WorldEditException { + @Override + public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tile) throws WorldEditException { return false; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java index 426cbc32a..c113c720c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java @@ -3,10 +3,12 @@ package com.fastasyncworldedit.core.extent.clipboard; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.jnbt.streamer.IntValueReader; import com.fastasyncworldedit.core.math.IntTriple; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.util.MainUtil; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.biome.BiomeType; @@ -262,6 +264,12 @@ public class MemoryOptimizedClipboard extends LinearClipboard { return true; } + @Override + public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tile) throws WorldEditException { + // TODO replace + return setTile(x, y, z, new CompoundTag(tile.linTag())); + } + @Override public > boolean setBlock(int x, int y, int z, B block) { return setBlock(getIndex(x, y, z), block); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java index 2edb9cb51..aa608be05 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java @@ -1,7 +1,7 @@ package com.fastasyncworldedit.core.extent.clipboard; import com.fastasyncworldedit.core.Fawe; -import com.sk89q.jnbt.CompoundTag; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; @@ -106,7 +106,7 @@ public abstract class ReadOnlyClipboard extends SimpleClipboard { } @Override - public boolean setTile(int x, int y, int z, CompoundTag tag) { + public boolean tile(int x, int y, int z, FaweCompoundTag tag) { throw new UnsupportedOperationException("Clipboard is immutable"); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java index 8b6aa6cc8..55e249740 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java @@ -5,6 +5,7 @@ import com.fastasyncworldedit.core.extent.clipboard.SimpleClipboard; import com.fastasyncworldedit.core.internal.io.ResettableFileInputStream; import com.fastasyncworldedit.core.internal.io.VarIntStreamIterator; import com.fastasyncworldedit.core.math.MutableBlockVector3; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.util.IOUtil; import com.fastasyncworldedit.core.util.MathMan; import com.sk89q.jnbt.CompoundTag; @@ -626,12 +627,11 @@ public class FastSchematicReaderV3 implements ClipboardReader { } private EntityTransformer provideTileEntityTransformer(Clipboard clipboard) { - //noinspection deprecation - return (x, y, z, id, tag) -> clipboard.setTile( + return (x, y, z, id, tag) -> clipboard.tile( MathMan.roundInt(x + clipboard.getMinimumPoint().x()), MathMan.roundInt(y + clipboard.getMinimumPoint().y()), MathMan.roundInt(z + clipboard.getMinimumPoint().z()), - new CompoundTag(tag) + FaweCompoundTag.of(tag) ); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/ArrayFilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/ArrayFilterBlock.java index 362f869ac..2e9263cea 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/ArrayFilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/ArrayFilterBlock.java @@ -1,5 +1,6 @@ package com.fastasyncworldedit.core.extent.filter.block; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; @@ -105,6 +106,11 @@ public class ArrayFilterBlock extends AbstractExtentFilterBlock { return getExtent().setBlock(x, y, z, block); } + @Override + public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tile) throws WorldEditException { + return false; // class is unused + deprecated, do not care about impl + } + @Override public boolean setBiome(int x, int y, int z, BiomeType biome) { return getExtent().setBiome(x, y, z, biome); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java index 579f04a9a..b1862987f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java @@ -1,6 +1,7 @@ package com.fastasyncworldedit.core.extent.filter.block; import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.FilterBlockMask; import com.fastasyncworldedit.core.queue.IBlocks; @@ -13,6 +14,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -20,6 +22,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.registry.BlockMaterial; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -259,8 +262,9 @@ public class CharFilterBlock extends ChunkFilterBlock { final BlockState state = getBlock(); final BlockMaterial material = state.getMaterial(); if (material.hasContainer()) { - final CompoundTag tag = get.getTile(x, y + yy, z); - return state.toBaseBlock(tag); + final FaweCompoundTag tag = get.tile(x, y + yy, z); + assert tag != null : "has container but is null"; + return state.toBaseBlock(tag.linTag()); } return state.toBaseBlock(); } @@ -268,16 +272,28 @@ public class CharFilterBlock extends ChunkFilterBlock { @Override public void setFullBlock(BaseBlock block) { delegate.set(this, block.getOrdinalChar()); - final CompoundTag nbt = block.getNbtData(); + final LazyReference nbt = block.getNbtReference(); if (nbt != null) { // TODO optimize check via ImmutableBaseBlock - set.setTile(x, yy + y, z, nbt); + set.tile(x, yy + y, z, FaweCompoundTag.of(nbt)); } } @Override - public final CompoundTag getNbtData() { - return get.getTile(x, y + yy, z); + public @Nullable LinCompoundTag getNbt() { + final FaweCompoundTag tile = get.tile(x, y + yy, z); + if (tile == null) { + return null; + } + return tile.linTag(); } + + @Override + public void setNbt(@Nullable final LinCompoundTag nbtData) { + if (nbtData != null) { + set.tile(x, y + yy, z, FaweCompoundTag.of(nbtData)); + } + } + /* NORTH(Vector3.at(0, 0, -1), Flag.CARDINAL, 3, 1), EAST(Vector3.at(1, 0, 0), Flag.CARDINAL, 0, 2), @@ -286,9 +302,9 @@ public class CharFilterBlock extends ChunkFilterBlock { */ @Override - public void setNbtData(CompoundTag tag) { - if (tag != null) { - set.setTile(x, y + yy, z, tag); + public void setNbtReference(@Nullable final LazyReference nbtData) { + if (nbtData != null) { + set.tile(x, y + yy, z, FaweCompoundTag.of(nbtData)); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/FilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/FilterBlock.java index 3565c696f..c35f549a2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/FilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/FilterBlock.java @@ -1,5 +1,6 @@ package com.fastasyncworldedit.core.extent.filter.block; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.TileEntityBlock; @@ -35,17 +36,6 @@ public abstract class FilterBlock extends BlockVector3 implements Extent, TileEn public abstract BiomeType getBiome(); - @Override - public abstract CompoundTag getNbtData(); - - @Override - public abstract void setNbtData(@Nullable CompoundTag nbtData); - - @Override - public boolean hasNbtData() { - return getNbtData() != null; - } - @Override public BlockVector3 getMinimumPoint() { return getExtent().getMinimumPoint(); @@ -61,10 +51,9 @@ public abstract class FilterBlock extends BlockVector3 implements Extent, TileEn return getExtent().getBlock(x, y, z); } - @Override - public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { - return getExtent().setTile(x, y, z, tile); + public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tile) throws WorldEditException { + return getExtent().tile(x, y, z, tile); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java index 84c1193eb..3e60cb4eb 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java @@ -4,11 +4,12 @@ import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.extent.HistoryExtent; import com.fastasyncworldedit.core.extent.processor.ProcessorScope; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunk; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; -import com.fastasyncworldedit.core.util.MainUtil; +import com.fastasyncworldedit.core.util.NbtUtils; import com.fastasyncworldedit.core.util.TaskManager; import com.google.common.util.concurrent.Futures; import com.sk89q.jnbt.CompoundTag; @@ -32,9 +33,12 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypesCache; import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinCompoundTag; import org.jetbrains.annotations.ApiStatus; +import javax.annotation.Nonnull; import java.io.IOException; +import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Objects; @@ -123,37 +127,38 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { int bx = chunk.getX() << 4; int bz = chunk.getZ() << 4; - Map tilesFrom = get.getTiles(); - Map tilesTo = set.getTiles(); + Map tilesFrom = get.tiles(); + Map tilesTo = set.tiles(); if (!tilesFrom.isEmpty()) { - for (Map.Entry entry : tilesFrom.entrySet()) { + for (Map.Entry entry : tilesFrom.entrySet()) { BlockVector3 pos = entry.getKey(); BlockState fromBlock = get.getBlock(pos.x() & 15, pos.y(), pos.z() & 15); BlockState toBlock = set.getBlock(pos.x() & 15, pos.y(), pos.z() & 15); if (fromBlock != toBlock || tilesTo.containsKey(pos)) { - addTileRemove(MainUtil.setPosition(entry.getValue(), entry.getKey().x(), entry.getKey().y(), - entry.getKey().z())); + addTileRemove(NbtUtils.withPosition(entry.getValue(), entry.getKey().x(), entry.getKey().y(), + entry.getKey().z() + )); } } } if (!tilesTo.isEmpty()) { - for (Map.Entry entry : tilesTo.entrySet()) { + for (Map.Entry entry : tilesTo.entrySet()) { BlockVector3 pos = entry.getKey(); - addTileCreate(MainUtil.setPosition(entry.getValue(), pos.x() + bx, pos.y(), pos.z() + bz)); + addTileCreate(NbtUtils.withPosition(entry.getValue(), pos.x() + bx, pos.y(), pos.z() + bz)); } } Set entRemoves = set.getEntityRemoves(); if (!entRemoves.isEmpty()) { for (UUID uuid : entRemoves) { - CompoundTag found = get.getEntity(uuid); + FaweCompoundTag found = get.entity(uuid); if (found != null) { addEntityRemove(found); } } } - Set ents = set.getEntities(); + Collection ents = set.entities(); if (!ents.isEmpty()) { - for (CompoundTag tag : ents) { + for (FaweCompoundTag tag : ents) { addEntityCreate(tag); } } @@ -204,9 +209,9 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { BiomeType[] biomeSection = biomes[layer - set.getMinSectionPosition()]; int index = 0; int yy = layer << 4; - for (int y = 0; y < 16; y+= 4) { - for (int z = 0; z < 16; z+= 4) { - for (int x = 0; x < 16; x+= 4, index++) { + for (int y = 0; y < 16; y += 4) { + for (int z = 0; z < 16; z += 4) { + for (int x = 0; x < 16; x += 4, index++) { BiomeType newBiome = biomeSection[index]; if (newBiome != null) { BiomeType oldBiome = get.getBiomeType(x, yy + y, z); @@ -237,13 +242,62 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { return ProcessorScope.READING_SET_BLOCKS; } - public abstract void addTileCreate(CompoundTag tag); + @Deprecated(forRemoval = true, since = "TODO") + public void addTileCreate(CompoundTag tag) { + addTileCreate(adapt(tag)); + } - public abstract void addTileRemove(CompoundTag tag); + @SuppressWarnings({"deprecation"}) + private static @Nonnull FaweCompoundTag adapt(CompoundTag tag) { + return FaweCompoundTag.of(tag.toLinTag()); + } - public abstract void addEntityRemove(CompoundTag tag); + /** + * Creates a tile/block entity create change to this change set. + * + * @param tag the tile/block entity to add. + * @since TODO + */ + public abstract void addTileCreate(FaweCompoundTag tag); - public abstract void addEntityCreate(CompoundTag tag); + @Deprecated(forRemoval = true, since = "TODO") + public void addTileRemove(CompoundTag tag) { + addTileRemove(adapt(tag)); + } + + /** + * Creates a tile/block entity remove change to this change set. + * + * @param tag the tile/block entity to remove. + * @since TODO + */ + public abstract void addTileRemove(FaweCompoundTag tag); + + @Deprecated(forRemoval = true, since = "TODO") + public void addEntityRemove(CompoundTag tag) { + addEntityRemove(adapt(tag)); + } + + /** + * Creates an entity remove change to this change set. + * + * @param tag the entity to remove. + * @since TODO + */ + public abstract void addEntityRemove(FaweCompoundTag tag); + + @Deprecated(forRemoval = true, since = "TODO") + public void addEntityCreate(CompoundTag tag) { + addEntityCreate(adapt(tag)); + } + + /** + * Creates an entity create change to this change set. + * + * @param tag the entity to add. + * @since TODO + */ + public abstract void addEntityCreate(FaweCompoundTag tag); public abstract void addBiomeChange(int x, int y, int z, BiomeType from, BiomeType to); @@ -280,13 +334,15 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { } public void add(EntityCreate change) { - CompoundTag tag = change.state.getNbtData(); - addEntityCreate(MainUtil.setEntityInfo(tag, change.getEntity())); + LinCompoundTag tag = change.state.getNbt(); + assert tag != null; + addEntityCreate(FaweCompoundTag.of(NbtUtils.withEntityInfo(tag, change.getEntity()))); } public void add(EntityRemove change) { - CompoundTag tag = change.state.getNbtData(); - addEntityRemove(MainUtil.setEntityInfo(tag, change.getEntity())); + LinCompoundTag tag = change.state.getNbt(); + assert tag != null; + addEntityRemove(FaweCompoundTag.of(NbtUtils.withEntityInfo(tag, change.getEntity()))); } @Override @@ -304,9 +360,9 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { public void add(BlockChange change) { try { - BlockVector3 loc = change.getPosition(); + BlockVector3 loc = change.position(); BaseBlock from = change.previous(); - BaseBlock to = change.getCurrent(); + BaseBlock to = change.current(); add(loc, from, to); } catch (Exception e) { LOGGER.catching(e); @@ -326,31 +382,28 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { public void add(int x, int y, int z, BaseBlock from, BaseBlock to) { try { - if (from.hasNbtData()) { - CompoundTag nbt = from.getNbtData(); - assert nbt != null; - addTileRemove(MainUtil.setPosition(nbt, x, y, z)); + LinCompoundTag nbt = from.getNbt(); + if (nbt != null) { + addTileRemove(FaweCompoundTag.of(NbtUtils.withPosition(nbt, x, y, z))); } - if (to.hasNbtData()) { - CompoundTag nbt = to.getNbtData(); - assert nbt != null; - addTileCreate(MainUtil.setPosition(nbt, x, y, z)); + nbt = to.getNbt(); + if (nbt != null) { + addTileCreate(FaweCompoundTag.of(NbtUtils.withPosition(nbt, x, y, z))); } int combinedFrom = from.getOrdinal(); int combinedTo = to.getOrdinal(); add(x, y, z, combinedFrom, combinedTo); } catch (Exception e) { - e.printStackTrace(); + LOGGER.catching(e); } } public void add(int x, int y, int z, int combinedFrom, BaseBlock to) { try { - if (to.hasNbtData()) { - CompoundTag nbt = to.getNbtData(); - assert nbt != null; - addTileCreate(MainUtil.setPosition(nbt, x, y, z)); + LinCompoundTag nbt = to.getNbt(); + if (nbt != null) { + addTileCreate(FaweCompoundTag.of(NbtUtils.withPosition(nbt, x, y, z))); } int combinedTo = to.getInternalId(); add(x, y, z, combinedFrom, combinedTo); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractDelegateChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractDelegateChangeSet.java index f3f0cdae4..e84888848 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractDelegateChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractDelegateChangeSet.java @@ -1,6 +1,6 @@ package com.fastasyncworldedit.core.history.changeset; -import com.sk89q.jnbt.CompoundTag; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.inventory.BlockBag; @@ -46,26 +46,6 @@ public class AbstractDelegateChangeSet extends AbstractChangeSet { parent.flush(); } - @Override - public void addTileCreate(CompoundTag tag) { - parent.addTileCreate(tag); - } - - @Override - public void addTileRemove(CompoundTag tag) { - parent.addTileRemove(tag); - } - - @Override - public void addEntityRemove(CompoundTag tag) { - parent.addEntityRemove(tag); - } - - @Override - public void addEntityCreate(CompoundTag tag) { - parent.addEntityCreate(tag); - } - @Override public void addBiomeChange(int x, int y, int z, BiomeType from, BiomeType to) { parent.addBiomeChange(x, y, z, from, to); @@ -146,6 +126,26 @@ public class AbstractDelegateChangeSet extends AbstractChangeSet { return parent.forwardIterator(); } + @Override + public void addTileCreate(final FaweCompoundTag tag) { + parent.addTileCreate(tag); + } + + @Override + public void addTileRemove(final FaweCompoundTag tag) { + parent.addTileRemove(tag); + } + + @Override + public void addEntityRemove(final FaweCompoundTag tag) { + parent.addEntityRemove(tag); + } + + @Override + public void addEntityCreate(final FaweCompoundTag tag) { + parent.addEntityCreate(tag); + } + @Override public void close() throws IOException { parent.close(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/BlockBagChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/BlockBagChangeSet.java index e17a78765..8c65be084 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/BlockBagChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/BlockBagChangeSet.java @@ -1,8 +1,6 @@ package com.fastasyncworldedit.core.history.changeset; import com.fastasyncworldedit.core.FaweCache; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.extent.inventory.BlockBagException; import com.sk89q.worldedit.extent.inventory.UnplaceableBlockException; @@ -109,13 +107,4 @@ public class BlockBagChangeSet extends AbstractDelegateChangeSet { super.add(x, y, z, combinedFrom, combinedTo); } - @Override - public void addTileCreate(CompoundTag nbt) { - if (nbt.containsKey("items")) { - Map> map = new HashMap<>(nbt.getValue()); - map.remove("items"); - } - super.addTileCreate(nbt); - } - } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java index 211a71303..613b8def8 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java @@ -10,6 +10,7 @@ import com.fastasyncworldedit.core.history.change.MutableTileChange; import com.fastasyncworldedit.core.internal.exception.FaweSmallEditUnsupportedException; import com.fastasyncworldedit.core.internal.io.FaweInputStream; import com.fastasyncworldedit.core.internal.io.FaweOutputStream; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.util.MainUtil; import com.fastasyncworldedit.core.util.MathMan; import com.sk89q.jnbt.CompoundTag; @@ -21,9 +22,12 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockTypes; +import org.enginehub.linbus.stream.LinBinaryIO; +import org.enginehub.linbus.tree.LinRootEntry; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.DataOutput; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; @@ -398,56 +402,44 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { } @Override - public void addTileCreate(CompoundTag tag) { - if (tag == null) { - return; - } + public void addTileCreate(final FaweCompoundTag tag) { blockSize++; try { - NBTOutputStream nbtos = getTileCreateOS(); - nbtos.writeTag(tag); + DataOutput nbtos = getTileCreateOS(); + LinBinaryIO.write(nbtos, new LinRootEntry("tile-create", tag.linTag())); } catch (IOException e) { e.printStackTrace(); } } @Override - public void addTileRemove(CompoundTag tag) { - if (tag == null) { - return; - } + public void addTileRemove(final FaweCompoundTag tag) { blockSize++; try { - NBTOutputStream nbtos = getTileRemoveOS(); - nbtos.writeTag(tag); + DataOutput nbtos = getTileRemoveOS(); + LinBinaryIO.write(nbtos, new LinRootEntry("tile-remove", tag.linTag())); } catch (IOException e) { e.printStackTrace(); } } @Override - public void addEntityRemove(CompoundTag tag) { - if (tag == null) { - return; - } + public void addEntityRemove(final FaweCompoundTag tag) { blockSize++; try { - NBTOutputStream nbtos = getEntityRemoveOS(); - nbtos.writeTag(tag); + DataOutput nbtos = getEntityRemoveOS(); + LinBinaryIO.write(nbtos, new LinRootEntry("entity-remove", tag.linTag())); } catch (IOException e) { e.printStackTrace(); } } @Override - public void addEntityCreate(CompoundTag tag) { - if (tag == null) { - return; - } + public void addEntityCreate(final FaweCompoundTag tag) { blockSize++; try { - NBTOutputStream nbtos = getEntityCreateOS(); - nbtos.writeTag(tag); + DataOutput nbtos = getEntityCreateOS(); + LinBinaryIO.write(nbtos, new LinRootEntry("entity-create", tag.linTag())); } catch (IOException e) { e.printStackTrace(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/NullChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/NullChangeSet.java index 2a60b3913..99711b6cc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/NullChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/NullChangeSet.java @@ -1,6 +1,6 @@ package com.fastasyncworldedit.core.history.changeset; -import com.sk89q.jnbt.CompoundTag; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.history.change.Change; import com.sk89q.worldedit.world.World; @@ -25,22 +25,22 @@ public class NullChangeSet extends AbstractChangeSet { } @Override - public final void addTileCreate(CompoundTag tag) { + public void addTileCreate(final FaweCompoundTag tag) { } @Override - public final void addTileRemove(CompoundTag tag) { + public void addTileRemove(final FaweCompoundTag tag) { } @Override - public final void addEntityRemove(CompoundTag tag) { + public void addEntityRemove(final FaweCompoundTag tag) { } @Override - public final void addEntityCreate(CompoundTag tag) { + public void addEntityCreate(final FaweCompoundTag tag) { } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/nbt/EagerFaweCompoundTag.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/nbt/EagerFaweCompoundTag.java new file mode 100644 index 000000000..c41d8db1d --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/nbt/EagerFaweCompoundTag.java @@ -0,0 +1,7 @@ +package com.fastasyncworldedit.core.nbt; + +import org.enginehub.linbus.tree.LinCompoundTag; + +record EagerFaweCompoundTag(LinCompoundTag linTag) implements FaweCompoundTag { + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/nbt/FaweCompoundTag.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/nbt/FaweCompoundTag.java new file mode 100644 index 000000000..a244f7964 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/nbt/FaweCompoundTag.java @@ -0,0 +1,44 @@ +package com.fastasyncworldedit.core.nbt; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import org.enginehub.linbus.tree.LinCompoundTag; + +/** + * A wrapper around compound tags, potentially lazily transformed. + * @since TODO + */ +public sealed interface FaweCompoundTag permits EagerFaweCompoundTag, LazyFaweCompoundTag { + + /** + * {@return a lazy compound component backed by a lazy reference} + * @param lazyReference the lazy reference to the actual compound tag + */ + static FaweCompoundTag of(LazyReference lazyReference) { + return new LazyFaweCompoundTag(lazyReference::getValue); + } + + /** + * {@return a lazy compound component backed by a supplier} + * Invocations to the supplier are memoized. + * @param supplier the supplier for the actual compound tag + */ + static FaweCompoundTag of(Supplier supplier) { + return new LazyFaweCompoundTag(Suppliers.memoize(supplier)); + } + + /** + * {@return a direct reference tho the given compound tag} + * @param linCompoundTag the tag to wrap + */ + static FaweCompoundTag of(LinCompoundTag linCompoundTag) { + return new EagerFaweCompoundTag(linCompoundTag); + } + + /** + * {@return the underlying tag} + */ + LinCompoundTag linTag(); + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/nbt/LazyFaweCompoundTag.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/nbt/LazyFaweCompoundTag.java new file mode 100644 index 000000000..afd0e4e48 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/nbt/LazyFaweCompoundTag.java @@ -0,0 +1,14 @@ +package com.fastasyncworldedit.core.nbt; + +import org.enginehub.linbus.tree.LinCompoundTag; + +import java.util.function.Supplier; + +record LazyFaweCompoundTag(Supplier linTagSupplier) implements FaweCompoundTag { + + @Override + public LinCompoundTag linTag() { + return this.linTagSupplier().get(); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java index ff6842c0a..b14b7b39d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java @@ -3,6 +3,8 @@ package com.fastasyncworldedit.core.queue; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.internal.io.FastByteArrayOutputStream; import com.fastasyncworldedit.core.internal.io.FaweOutputStream; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; +import com.fastasyncworldedit.core.util.collection.AdaptedMap; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Capability; @@ -12,10 +14,13 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.registry.BlockRegistry; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; +import java.util.Collection; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.IntStream; /** @@ -54,11 +59,38 @@ public interface IBlocks extends Trimable { BlockState getBlock(int x, int y, int z); - Map getTiles(); + @Deprecated(forRemoval = true, since = "TODO") + default Map getTiles() { + return AdaptedMap.immutable(tiles(), pos -> pos, IBlocks::toCompoundTag); + } - CompoundTag getTile(int x, int y, int z); + Map tiles(); - Set getEntities(); + @Deprecated(forRemoval = true, since = "TODO") + default CompoundTag getTile(int x, int y, int z) { + final FaweCompoundTag tile = tile(x, y, z); + if (tile == null) { + return null; + } + return toCompoundTag(tile); + } + + @SuppressWarnings({"deprecation"}) + private static @Nonnull CompoundTag toCompoundTag(FaweCompoundTag tile) { + return new CompoundTag(tile.linTag()); + } + + @Nullable + FaweCompoundTag tile(int x, int y, int z); + + @Deprecated(forRemoval = true, since = "TODO") + default Set getEntities() { + return entities().stream() + .map(IBlocks::toCompoundTag) + .collect(Collectors.toSet()); + } + + Collection entities(); BiomeType getBiomeType(int x, int y, int z); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java index 534a96fac..615f5fb50 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java @@ -1,11 +1,7 @@ package com.fastasyncworldedit.core.queue; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.DoubleTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.NBTUtils; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; +import com.fastasyncworldedit.core.util.NbtUtils; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; @@ -16,6 +12,12 @@ 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 org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import java.util.ArrayList; import java.util.HashMap; @@ -39,9 +41,9 @@ public interface IChunkExtent extends Extent { } @Override - default boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { + default boolean tile(int x, int y, int z, FaweCompoundTag tile) throws WorldEditException { final IChunk chunk = getOrCreateChunk(x >> 4, z >> 4); - return chunk.setTile(x & 15, y, z & 15, tile); + return chunk.tile(x & 15, y, z & 15, tile); } @Override @@ -124,19 +126,19 @@ public interface IChunkExtent extends Extent { @Override default Entity createEntity(Location location, BaseEntity entity, UUID uuid) { final IChunk chunk = getOrCreateChunk(location.getBlockX() >> 4, location.getBlockZ() >> 4); - Map> map = new HashMap<>(entity.getNbtData().getValue()); //do not modify original entity data - map.put("Id", new StringTag(entity.getType().getName())); + Map> map = new HashMap<>(entity.getNbt().value()); //do not modify original entity data + map.put("Id", LinStringTag.of(entity.getType().getName())); //Set pos - List posList = new ArrayList<>(); - posList.add(new DoubleTag(location.x())); - posList.add(new DoubleTag(location.y())); - posList.add(new DoubleTag(location.z())); - map.put("Pos", new ListTag(DoubleTag.class, posList)); + List posList = new ArrayList<>(); + posList.add(LinDoubleTag.of(location.x())); + posList.add(LinDoubleTag.of(location.y())); + posList.add(LinDoubleTag.of(location.z())); + map.put("Pos", LinListTag.of(LinTagType.doubleTag(), posList)); - NBTUtils.addUUIDToMap(map, uuid); + NbtUtils.addUUIDToMap(map, uuid); - chunk.setEntity(new CompoundTag(map)); + chunk.entity(FaweCompoundTag.of(LinCompoundTag.of(map))); return new IChunkEntity(this, location, uuid, entity); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java index b2ac59cb2..1ead25284 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java @@ -1,6 +1,7 @@ package com.fastasyncworldedit.core.queue; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.extent.InputExtent; import com.sk89q.worldedit.math.BlockVector3; @@ -46,7 +47,26 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent, ITileInput { > T call(IChunkSet set, Runnable finalize); - CompoundTag getEntity(UUID uuid); + @Deprecated(forRemoval = true, since = "TODO") + default CompoundTag getEntity(UUID uuid) { + final FaweCompoundTag entity = entity(uuid); + if (entity == null) { + return null; + } + return new CompoundTag(entity.linTag()); + } + + /** + * {@return the compound tag describing the entity with the given UUID, if any} + * @param uuid the uuid of the entity + */ + @Nullable FaweCompoundTag entity(UUID uuid); + + @Override + @Deprecated(forRemoval = true, since = "TODO") + default CompoundTag getTile(int x, int y, int z) { + return IBlocks.super.getTile(x, y, z); + } boolean isCreateCopy(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java index bc621e66a..13400f769 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java @@ -1,7 +1,9 @@ package com.fastasyncworldedit.core.queue; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.OutputExtent; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.math.BlockVector3; @@ -36,7 +38,12 @@ public interface IChunkSet extends IBlocks, OutputExtent { boolean isEmpty(); @Override - boolean setTile(int x, int y, int z, CompoundTag tile); + @Deprecated(forRemoval = true, since = "TODO") + default boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { + return tile(x, y, z, FaweCompoundTag.of(tile.toLinTag())); + } + + boolean tile(int x, int y, int z, FaweCompoundTag tag); @Override void setBlockLight(int x, int y, int z, int value); @@ -53,7 +60,12 @@ public interface IChunkSet extends IBlocks, OutputExtent { void setFullBright(int layer); - void setEntity(CompoundTag tag); + @Deprecated(forRemoval = true, since = "TODO") + default void setEntity(CompoundTag tag) { + entity(FaweCompoundTag.of(tag::toLinTag)); + } + + void entity(FaweCompoundTag tag); void removeEntity(UUID uuid); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/ITileInput.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/ITileInput.java index 5d0641c81..eb0503858 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/ITileInput.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/ITileInput.java @@ -2,6 +2,7 @@ package com.fastasyncworldedit.core.queue; import com.sk89q.jnbt.CompoundTag; +@Deprecated(forRemoval = true, since = "TODO") public interface ITileInput { CompoundTag getTile(int x, int y, int z); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/BitSetBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/BitSetBlocks.java index ae976777c..76f2191ed 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/BitSetBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/BitSetBlocks.java @@ -2,9 +2,9 @@ package com.fastasyncworldedit.core.queue.implementation.blocks; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.util.collection.MemBlockSet; -import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockState; @@ -13,6 +13,7 @@ import com.sk89q.worldedit.world.block.BlockTypesCache; import javax.annotation.Nullable; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Set; @@ -74,7 +75,7 @@ public class BitSetBlocks implements IChunkSet { } @Override - public boolean setTile(int x, int y, int z, CompoundTag tile) { + public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tag) { return false; } @@ -107,7 +108,7 @@ public class BitSetBlocks implements IChunkSet { } @Override - public void setEntity(CompoundTag tag) { + public void entity(final FaweCompoundTag tag) { } @Override @@ -181,18 +182,18 @@ public class BitSetBlocks implements IChunkSet { } @Override - public Map getTiles() { + public Map tiles() { return Collections.emptyMap(); } @Override - public CompoundTag getTile(int x, int y, int z) { + public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) { return null; } @Override - public Set getEntities() { - return Collections.emptySet(); + public Collection entities() { + return Collections.emptyList(); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharGetBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharGetBlocks.java index 2c89a7108..cd1c1b76f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharGetBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharGetBlocks.java @@ -1,5 +1,6 @@ package com.fastasyncworldedit.core.queue.implementation.blocks; +import com.fastasyncworldedit.core.queue.IBlocks; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; import com.sk89q.worldedit.world.block.BaseBlock; @@ -20,7 +21,7 @@ public abstract class CharGetBlocks extends CharBlocks implements IChunkGet { @Override public BaseBlock getFullBlock(int x, int y, int z) { BlockState state = BlockTypesCache.states[get(x, y, z)]; - return state.toBaseBlock(this, x, y, z); + return state.toBaseBlock((IBlocks) this, x, y, z); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharSetBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharSetBlocks.java index da28e5925..8d7c059ed 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharSetBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharSetBlocks.java @@ -4,16 +4,18 @@ import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.math.BlockVector3ChunkMap; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.Pool; -import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypesCache; +import javax.annotation.Nullable; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; @@ -36,8 +38,8 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet { public BiomeType[][] biomes; public char[][] light; public char[][] skyLight; - public BlockVector3ChunkMap tiles; - public HashSet entities; + public BlockVector3ChunkMap tiles; + public HashSet entities; public HashSet entityRemoves; public EnumMap heightMaps; private boolean fastMode = false; @@ -71,17 +73,17 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet { } @Override - public Map getTiles() { + public Map tiles() { return tiles == null ? Collections.emptyMap() : tiles; } @Override - public CompoundTag getTile(int x, int y, int z) { + public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) { return tiles == null ? null : tiles.get(x, y, z); } @Override - public Set getEntities() { + public Collection entities() { return entities == null ? Collections.emptySet() : entities; } @@ -132,12 +134,12 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet { } @Override - public boolean setTile(int x, int y, int z, CompoundTag tile) { + public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tag) { if (tiles == null) { tiles = new BlockVector3ChunkMap<>(); } updateSectionIndexRange(y >> 4); - tiles.put(x, y, z, tile); + tiles.put(x, y, z, tag); return true; } @@ -259,7 +261,7 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet { } @Override - public void setEntity(CompoundTag tag) { + public void entity(final FaweCompoundTag tag) { if (entities == null) { entities = new HashSet<>(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/NullChunkGet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/NullChunkGet.java index 042870666..273f44952 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/NullChunkGet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/NullChunkGet.java @@ -2,10 +2,10 @@ package com.fastasyncworldedit.core.queue.implementation.blocks; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBlocks; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; -import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; @@ -15,9 +15,9 @@ import com.sk89q.worldedit.world.block.BlockTypes; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.Collection; import java.util.Collections; import java.util.Map; -import java.util.Set; import java.util.UUID; import java.util.concurrent.Future; @@ -48,24 +48,19 @@ public final class NullChunkGet implements IChunkGet { return BlockTypes.AIR.getDefaultState(); } - @Nonnull - public Map getTiles() { + @Override + public Map tiles() { return Collections.emptyMap(); } - @Nullable - public CompoundTag getTile(int x, int y, int z) { + @Override + public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) { return null; } - @Nullable - public Set getEntities() { - return null; - } - - @Nullable - public CompoundTag getEntity(@Nonnull UUID uuid) { - return null; + @Override + public Collection entities() { + return Collections.emptyList(); } @Override @@ -123,6 +118,11 @@ public final class NullChunkGet implements IChunkGet { return null; } + @Override + public @Nullable FaweCompoundTag entity(final UUID uuid) { + return null; + } + @Nonnull public char[] load(int layer) { return FaweCache.INSTANCE.EMPTY_CHAR_4096; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java index 90ae6b32e..c21e932a9 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java @@ -4,9 +4,9 @@ import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.math.BlockVector3ChunkMap; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBlocks; import com.fastasyncworldedit.core.queue.IChunkSet; -import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; @@ -17,6 +17,7 @@ import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; @@ -44,8 +45,8 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks { private BiomeType[][] biomes; private char[][] light; private char[][] skyLight; - private BlockVector3ChunkMap tiles; - private HashSet entities; + private BlockVector3ChunkMap tiles; + private HashSet entities; private HashSet entityRemoves; private Map heightMaps; private boolean fastMode; @@ -64,8 +65,8 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks { int sectionCount, char[][] light, char[][] skyLight, - BlockVector3ChunkMap tiles, - HashSet entities, + BlockVector3ChunkMap tiles, + HashSet entities, HashSet entityRemoves, Map heightMaps, char defaultOrdinal, @@ -116,18 +117,18 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks { } @Override - public Map getTiles() { + public Map tiles() { return tiles == null ? Collections.emptyMap() : tiles; } @Override - public CompoundTag getTile(int x, int y, int z) { + public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) { return tiles == null ? null : tiles.get(x, y, z); } @Override - public Set getEntities() { - return entities == null ? Collections.emptySet() : entities; + public Collection entities() { + return entities == null ? Collections.emptyList() : entities; } @Override @@ -268,12 +269,12 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks { } @Override - public boolean setTile(int x, int y, int z, CompoundTag tile) { + public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tag) { updateSectionIndexRange(y >> 4); if (tiles == null) { tiles = new BlockVector3ChunkMap<>(); } - tiles.put(x, y, z, tile); + tiles.put(x, y, z, tag); return true; } @@ -358,7 +359,7 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks { } @Override - public void setEntity(CompoundTag tag) { + public void entity(final FaweCompoundTag tag) { if (entities == null) { entities = new HashSet<>(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java index a7417eddf..7c36eb94c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java @@ -3,6 +3,7 @@ package com.fastasyncworldedit.core.queue.implementation.chunk; import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock; import com.fastasyncworldedit.core.extent.processor.EmptyBatchProcessor; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.IChunk; import com.fastasyncworldedit.core.queue.IChunkGet; @@ -11,7 +12,6 @@ import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.fastasyncworldedit.core.queue.implementation.ParallelQueueExtent; import com.fastasyncworldedit.core.util.MemUtil; -import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; @@ -22,6 +22,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; +import java.util.Collection; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -76,18 +77,8 @@ public class ChunkHolder> implements IQueueChunk { } @Override - public boolean setTile(int x, int y, int z, CompoundTag tag) { - return delegate.set(this).setTile(x, y, z, tag); - } - - @Override - public CompoundTag getTile(int x, int y, int z) { - return delegate.set(this).getTile(x, y, z); - } - - @Override - public void setEntity(CompoundTag tag) { - delegate.set(this).setEntity(tag); + public void entity(final FaweCompoundTag tag) { + delegate.set(this).entity(tag); } @Override @@ -163,11 +154,6 @@ public class ChunkHolder> implements IQueueChunk { return isInit; } - @Override - public CompoundTag getEntity(UUID uuid) { - return delegate.get(this).getEntity(uuid); - } - @Override public int setCreateCopy(boolean createCopy) { this.createCopy = createCopy; @@ -879,16 +865,6 @@ public class ChunkHolder> implements IQueueChunk { } }; - @Override - public Map getTiles() { - return delegate.get(this).getTiles(); - } - - @Override - public Set getEntities() { - return delegate.get(this).getEntities(); - } - @Override public boolean hasSection(int layer) { return chunkExisting != null && chunkExisting.hasSection(layer); @@ -946,6 +922,11 @@ public class ChunkHolder> implements IQueueChunk { return chunkSet == null || chunkSet.isEmpty(); } + @Override + public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tag) { + return false; + } + /** * Get or create the existing part of this chunk. */ @@ -1093,6 +1074,21 @@ public class ChunkHolder> implements IQueueChunk { return delegate.getBlock(this, x, y, z); } + @Override + public Map tiles() { + return delegate.get(this).tiles(); + } + + @Override + public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) { + return delegate.get(this).tile(x, y, z); + } + + @Override + public Collection entities() { + return delegate.get(this).entities(); + } + @Override public BaseBlock getFullBlock(int x, int y, int z) { return delegate.getFullBlock(this, x, y, z); @@ -1158,6 +1154,11 @@ public class ChunkHolder> implements IQueueChunk { return delegate.getHeightMap(this, type); } + @Override + public @Nullable FaweCompoundTag entity(final UUID uuid) { + return delegate.get(this).entity(uuid); + } + public interface IBlockDelegate { > IChunkGet get(ChunkHolder chunk); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java index 8cc6471ba..14107e83a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java @@ -2,10 +2,10 @@ package com.fastasyncworldedit.core.queue.implementation.chunk; import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.IQueueChunk; -import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.biome.BiomeType; @@ -16,6 +16,7 @@ import com.sk89q.worldedit.world.block.BlockTypes; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Set; @@ -53,13 +54,11 @@ public final class NullChunk implements IQueueChunk { return false; } - public boolean setTile(int x, int y, int z, @Nonnull CompoundTag tag) { + @Override + public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tag) { return false; } - public void setEntity(@Nonnull CompoundTag tag) { - } - public void removeEntity(@Nonnull UUID uuid) { } @@ -112,6 +111,10 @@ public final class NullChunk implements IQueueChunk { public void setFullBright(int layer) { } + @Override + public void entity(final FaweCompoundTag tag) { + } + public void removeSectionLighting(int layer, boolean sky) { } @@ -147,25 +150,26 @@ public final class NullChunk implements IQueueChunk { return BlockTypes.__RESERVED__.getDefaultState(); } + @Override + public Map tiles() { + return Collections.emptyMap(); + } + + @Override + public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) { + return null; + } + + @Override + public Collection entities() { + return Collections.emptyList(); + } + @Nonnull public BaseBlock getFullBlock(int x, int y, int z) { return BlockTypes.__RESERVED__.getDefaultState().toBaseBlock(); } - @Nonnull - public Map getTiles() { - return Collections.emptyMap(); - } - - @Nullable - public CompoundTag getTile(int x, int y, int z) { - return null; - } - - @Nonnull - public Set getEntities() { - return Collections.emptySet(); - } @Nullable public char[] load(int layer) { @@ -178,11 +182,6 @@ public final class NullChunk implements IQueueChunk { return null; } - @Nullable - public CompoundTag getEntity(@Nonnull UUID uuid) { - return null; - } - @Override public int setCreateCopy(boolean createCopy) { return -1; @@ -230,6 +229,11 @@ public final class NullChunk implements IQueueChunk { return null; } + @Override + public @Nullable FaweCompoundTag entity(final UUID uuid) { + return null; + } + public boolean trim(boolean aggressive) { return true; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java index 8ab673b77..115397788 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java @@ -34,6 +34,7 @@ import net.jpountz.lz4.LZ4Compressor; import net.jpountz.lz4.LZ4Factory; import net.jpountz.lz4.LZ4FastDecompressor; import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -424,8 +425,10 @@ public class MainUtil { * @param y New Y coordinate * @param z New Z coordinate * @return New tag + * @deprecated use {@link NbtUtils#withPosition} instead */ @Nonnull + @Deprecated(forRemoval = true, since = "TODO") public static CompoundTag setPosition(@Nonnull CompoundTag tag, int x, int y, int z) { Map> value = new HashMap<>(tag.getValue()); value.put("x", new IntTag(x)); @@ -440,8 +443,10 @@ public class MainUtil { * @param tag Tag to copy * @param entity Entity * @return New tag + * @deprecated use {@link NbtUtils#withEntityInfo(LinCompoundTag, Entity)} instead */ @Nonnull + @Deprecated(forRemoval = true, since = "TODO") public static CompoundTag setEntityInfo(@Nonnull CompoundTag tag, @Nonnull Entity entity) { Map> map = new HashMap<>(tag.getValue()); map.put("Id", new StringTag(entity.getState().getType().id())); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java index 07157e820..07a752131 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java @@ -1,17 +1,29 @@ package com.fastasyncworldedit.core.util; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.storage.InvalidFormatException; import org.enginehub.linbus.tree.LinByteTag; import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinIntArrayTag; import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinLongTag; import org.enginehub.linbus.tree.LinShortTag; import org.enginehub.linbus.tree.LinTag; import org.enginehub.linbus.tree.LinTagType; +import javax.annotation.Nonnull; import java.util.HashMap; import java.util.Map; +import java.util.UUID; -public class NbtUtils { +public final class NbtUtils { + + private NbtUtils() { + } /** * Get child tag of a NBT structure. @@ -79,4 +91,124 @@ public class NbtUtils { return value; } + /** + * Tries to extract UUID information from a compound tag + * + * @param compoundTag the compound tag to extract uuid information from + * @return the extracted UUID + * @since TODO + */ + public static UUID uuid(FaweCompoundTag compoundTag) { + final LinCompoundTag linTag = compoundTag.linTag(); + { + final LinIntArrayTag uuidTag = linTag.findTag("UUID", LinTagType.intArrayTag()); + if (uuidTag != null) { + int[] arr = uuidTag.value(); + return new UUID((long) arr[0] << 32 | (arr[1] & 0xFFFFFFFFL), (long) arr[2] << 32 | (arr[3] & 0xFFFFFFFFL)); + } + } + { + final LinLongTag uuidMostTag = linTag.findTag("UUIDMost", LinTagType.longTag()); + if (uuidMostTag != null) { + return new UUID(uuidMostTag.valueAsLong(), linTag.getTag("UUIDLeast", LinTagType.longTag()).valueAsLong()); + } + } + { + final LinLongTag uuidMostTag = linTag.findTag("WorldUUIDMost", LinTagType.longTag()); + if (uuidMostTag != null) { + return new UUID(uuidMostTag.valueAsLong(), linTag.getTag("WorldUUIDLeast", LinTagType.longTag()).valueAsLong()); + } + + } + { + final LinLongTag uuidMostTag = linTag.findTag("PersistentIDMSB", LinTagType.longTag()); + if (uuidMostTag != null) { + return new UUID(uuidMostTag.valueAsLong(), linTag.getTag("PersistentIDLSB", LinTagType.longTag()).valueAsLong()); + } + + } + throw new IllegalArgumentException("no uuid present"); + + } + + /** + * Create a copy of the tag and modify the (x, y, z) coordinates + * + * @param tag Tag to copy + * @param x New X coordinate + * @param y New Y coordinate + * @param z New Z coordinate + * @return New tag + * @since TODO + */ + public static @Nonnull LinCompoundTag withPosition(@Nonnull LinCompoundTag tag, int x, int y, int z) { + return tag.toBuilder() + .putInt("x", x) + .putInt("y", y) + .putInt("z", z) + .build(); + } + + /** + * Create a copy of the tag and modify the (x, y, z) coordinates + * + * @param tag Tag to copy + * @param x New X coordinate + * @param y New Y coordinate + * @param z New Z coordinate + * @return New tag + * @since TODO + */ + public static @Nonnull FaweCompoundTag withPosition(@Nonnull FaweCompoundTag tag, int x, int y, int z) { + return FaweCompoundTag.of(withPosition(tag.linTag(), x, y, z)); + } + + /** + * {@return a copy of the given tag with the Id and the Pos of the given entity} + * + * @param tag the tag to copy + * @param entity the entity to use the Id and the Pos from + * @since TODO + */ + public static @Nonnull LinCompoundTag withEntityInfo(@Nonnull LinCompoundTag tag, @Nonnull Entity entity) { + final LinCompoundTag.Builder builder = tag.toBuilder() + .putString("Id", entity.getState().getType().id()); + LinListTag pos = tag.findListTag("Pos", LinTagType.doubleTag()); + if (pos != null) { // TODO why only if pos != null? + Location loc = entity.getLocation(); + final LinListTag newPos = LinListTag.builder(LinTagType.doubleTag()) + .add(LinDoubleTag.of(loc.x())) + .add(LinDoubleTag.of(loc.y())) + .add(LinDoubleTag.of(loc.z())) + .build(); + builder.put("Pos", newPos); + } + return builder.build(); + } + + /** + * Adds a UUID to the given map + * + * @param map the map to insert to + * @param uuid the uuid to insert + * @since TODO + */ + public static void addUUIDToMap(Map> map, UUID uuid) { + int[] uuidArray = new int[4]; + uuidArray[0] = (int) (uuid.getMostSignificantBits() >> 32); + uuidArray[1] = (int) uuid.getMostSignificantBits(); + uuidArray[2] = (int) (uuid.getLeastSignificantBits() >> 32); + uuidArray[3] = (int) uuid.getLeastSignificantBits(); + map.put("UUID", LinIntArrayTag.of(uuidArray)); + + map.put("UUIDMost", LinLongTag.of(uuid.getMostSignificantBits())); + map.put("UUIDLeast", LinLongTag.of(uuid.getLeastSignificantBits())); + + map.put("WorldUUIDMost", LinLongTag.of(uuid.getMostSignificantBits())); + map.put("WorldUUIDLeast", LinLongTag.of(uuid.getLeastSignificantBits())); + + map.put("PersistentIDMSB", LinLongTag.of(uuid.getMostSignificantBits())); + map.put("PersistentIDLSB", LinLongTag.of(uuid.getLeastSignificantBits())); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/block/CompoundInput.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/block/CompoundInput.java index 4310d6523..481f8d54f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/block/CompoundInput.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/block/CompoundInput.java @@ -1,5 +1,7 @@ package com.fastasyncworldedit.core.world.block; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; +import com.fastasyncworldedit.core.queue.IBlocks; import com.fastasyncworldedit.core.queue.ITileInput; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -11,9 +13,21 @@ public enum CompoundInput { public BaseBlock get(BlockState state, ITileInput input, int x, int y, int z) { return state.toBaseBlock(input.getTile(x, y, z)); } + + @Override + public BaseBlock get(final BlockState state, final IBlocks blocks, final int x, final int y, final int z) { + final FaweCompoundTag tile = blocks.tile(x, y, z); + assert tile != null : "container without tile entity"; + return state.toBaseBlock(tile.linTag()); + } }; + @Deprecated(forRemoval = true, since = "TODO") public BaseBlock get(BlockState state, ITileInput input, int x, int y, int z) { return state.toBaseBlock(); } + + public BaseBlock get(BlockState state, IBlocks blocks, int x, int y, int z) { + return state.toBaseBlock(); + } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/WorldWrapper.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/WorldWrapper.java index 05616a414..616e90b37 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/WorldWrapper.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/WorldWrapper.java @@ -1,5 +1,6 @@ package com.fastasyncworldedit.core.wrappers; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.ExtentTraverser; @@ -187,8 +188,8 @@ public class WorldWrapper extends AbstractWorld { } @Override - public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { - return parent.setTile(x, y, z, tile); + public boolean tile(int x, int y, int z, FaweCompoundTag tile) throws WorldEditException { + return parent.tile(x, y, z, tile); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java index b742cb6f8..11143a6c7 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java @@ -172,7 +172,9 @@ public final class NBTUtils { * @param map Map to add uuid to * @param uuid {@link UUID} to add * @since 2.4.0 + * @deprecated use {@link com.fastasyncworldedit.core.util.NbtUtils#addUUIDToMap(Map, UUID)} instead */ + @Deprecated(forRemoval = true, since = "TODO") public static void addUUIDToMap(Map> map, UUID uuid) { int[] uuidArray = new int[4]; uuidArray[0] = (int) (uuid.getMostSignificantBits() >> 32); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java index f2d7dc884..267734247 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -25,6 +25,7 @@ import com.fastasyncworldedit.core.extent.HistoryExtent; import com.fastasyncworldedit.core.extent.NullExtent; import com.fastasyncworldedit.core.history.changeset.AbstractChangeSet; import com.fastasyncworldedit.core.internal.exception.FaweException; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.util.ExtentTraverser; @@ -425,8 +426,8 @@ public class AbstractDelegateExtent implements Extent { } @Override - public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { - return setBlock(x, y, z, getBlock(x, y, z).toBaseBlock(tile)); + public boolean tile(int x, int y, int z, FaweCompoundTag tile) throws WorldEditException { + return setBlock(x, y, z, getBlock(x, y, z).toBaseBlock(tile.linTag())); } //FAWE end 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 1b4420d27..9f73c8f5e 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 @@ -736,7 +736,6 @@ public interface Extent extends InputExtent, OutputExtent { default > int setBlocks(Region region, B block) throws MaxChangedBlocksException { checkNotNull(region); checkNotNull(block); - boolean hasNbt = block instanceof BaseBlock && block.hasNbtData(); int changes = 0; for (BlockVector3 pos : region) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/NullExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/NullExtent.java index 934b52204..b98e0f4b8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/NullExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/NullExtent.java @@ -19,8 +19,8 @@ package com.sk89q.worldedit.extent; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBatchProcessor; -import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; @@ -108,7 +108,7 @@ public class NullExtent implements Extent { } @Override - public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { + public boolean tile(int x, int y, int z, FaweCompoundTag tile) throws WorldEditException { return false; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java index 9346bf380..1e988b51f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.extent; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.math.MutableBlockVector3; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; @@ -68,7 +69,24 @@ public interface OutputExtent { return setBlock(MutableBlockVector3.get(x, y, z), block); } - boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException; + /** + * @deprecated use {@link #tile(int, int, int, FaweCompoundTag)} instead + */ + @Deprecated(forRemoval = true, since = "TODO") + default boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { + return tile(x, y, z, FaweCompoundTag.of(tile.toLinTag())); + } + + /** + * Sets a tile/block entity at the given location. + * @param x the x position + * @param y the y position + * @param z the z position + * @param tile the tile/block entity to set + * @return {@code true} if the tile/block entity was placed + * @since TODO + */ + boolean tile(int x, int y, int z, FaweCompoundTag tile) throws WorldEditException; /** * Check if this extent fully supports 3D biomes. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index cf4623739..e67c28abf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -23,6 +23,7 @@ import com.fastasyncworldedit.core.extent.clipboard.SimpleClipboard; import com.fastasyncworldedit.core.function.visitor.Order; import com.fastasyncworldedit.core.math.MutableBlockVector2; import com.fastasyncworldedit.core.math.OffsetBlockVector3; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.google.common.collect.Iterators; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEditException; @@ -200,16 +201,17 @@ public class BlockArrayClipboard implements Clipboard { //FAWE start @Override - public boolean setTile(int x, int y, int z, CompoundTag tag) { + public boolean tile(int x, int y, int z, FaweCompoundTag tag) { x -= offset.x(); y -= offset.y(); z -= offset.z(); - return getParent().setTile(x, y, z, tag); + return getParent().tile(x, y, z, tag); } + @Deprecated(forRemoval = true, since = "TODO") public boolean setTile(BlockVector3 position, CompoundTag tag) { - return setTile(position.x(), position.y(), position.z(), tag); + return tile(position.x(), position.y(), position.z(), FaweCompoundTag.of(tag.toLinTag())); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java index ee2789a33..d8dc989da 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 @@ -852,6 +852,7 @@ public abstract class BlockVector3 { return orDefault.getBiome(this); } + @Deprecated(forRemoval = true, since = "TODO") public CompoundTag getNbtData(Extent orDefault) { return orDefault.getFullBlock(x(), y(), z()).getNbtData(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestExtent.java index 2af8232af..5aedae6d9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestExtent.java @@ -19,7 +19,7 @@ package com.sk89q.worldedit.session.request; -import com.sk89q.jnbt.CompoundTag; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; @@ -119,8 +119,8 @@ public class RequestExtent implements Extent { //FAWE start @Override - public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { - return getExtent().setTile(x, y, z, tile); + public boolean tile(int x, int y, int z, FaweCompoundTag tile) throws WorldEditException { + return getExtent().tile(x, y, z, tile); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java index 0e962d746..d3ad7bfd9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -19,11 +19,11 @@ package com.sk89q.worldedit.world; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.blocks.NullChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.google.common.collect.ImmutableSet; -import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEditException; @@ -204,7 +204,7 @@ public class NullWorld extends AbstractWorld { //FAWE start @Override - public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { + public boolean tile(int x, int y, int z, FaweCompoundTag tile) throws WorldEditException { return false; } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java index ab93a4016..ea54b1c7a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.world.block; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.registry.state.PropertyKey; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEditException; @@ -262,15 +263,15 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { @Override public void applyTileEntity(OutputExtent output, int x, int y, int z) { - CompoundTag nbt = getNbtData(); + LinCompoundTag nbt = getNbt(); if (nbt != null) { - output.setTile(x, y, z, nbt); + output.tile(x, y, z, FaweCompoundTag.of(nbt)); } } @Override public BaseBlock withPropertyId(int propertyId) { - return getBlockType().withPropertyId(propertyId).toBaseBlock(getNbtData()); + return getBlockType().withPropertyId(propertyId).toBaseBlock(getNbtReference()); } @Override @@ -285,7 +286,7 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { @Override public BaseBlock with(PropertyKey property, V value) { - return toImmutableState().with(property, value).toBaseBlock(getNbtData()); + return toImmutableState().with(property, value).toBaseBlock(getNbtReference()); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index caa8ba919..824ad2b85 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -22,6 +22,7 @@ package com.sk89q.worldedit.world.block; import com.fastasyncworldedit.core.command.SuggestInputParseException; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.function.mask.SingleBlockStateMask; +import com.fastasyncworldedit.core.queue.IBlocks; import com.fastasyncworldedit.core.queue.ITileInput; import com.fastasyncworldedit.core.registry.state.PropertyKey; import com.fastasyncworldedit.core.util.MutableCharSequence; @@ -476,6 +477,12 @@ public class BlockState implements BlockStateHolder, Pattern { public BaseBlock toBaseBlock(ITileInput input, int x, int y, int z) { return compoundInput.get(this, input, x, y, z); } + + @Override + public BaseBlock toBaseBlock(final IBlocks blocks, final int x, final int y, final int z) { + return compoundInput.get(this, blocks, x, y, z); + } + //FAWE end @Override 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 f2ea08b67..808f8f23f 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 @@ -19,6 +19,7 @@ package com.sk89q.worldedit.world.block; +import com.fastasyncworldedit.core.queue.IBlocks; import com.fastasyncworldedit.core.queue.ITileInput; import com.fastasyncworldedit.core.registry.state.PropertyKey; import com.sk89q.jnbt.CompoundTag; @@ -201,6 +202,10 @@ public interface BlockStateHolder> extends TileEnt default BaseBlock toBaseBlock(ITileInput input, int x, int y, int z) { throw new UnsupportedOperationException("State is immutable"); } + + default BaseBlock toBaseBlock(IBlocks blocks, int x, int y, int z) { + throw new UnsupportedOperationException("State is immutable"); + } //FAWE end default String getAsString() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockMaterial.java index c8baea757..d37929a37 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockMaterial.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.world.registry; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.jnbt.CompoundTag; import javax.annotation.Nullable; @@ -185,7 +186,19 @@ public interface BlockMaterial { * @return default tile entity data */ @Nullable - CompoundTag getDefaultTile(); + default CompoundTag getDefaultTile() { + final FaweCompoundTag faweCompoundTag = defaultTile(); + if (faweCompoundTag == null) { + return null; + } + return new CompoundTag(faweCompoundTag.linTag()); + } + + /** + * {@return the default tile associated with this material, if any} + * @since TODO + */ + @Nullable FaweCompoundTag defaultTile(); /** * Get the map color. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java index 95743b80a..28b09a30e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.world.registry; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.jnbt.CompoundTag; import javax.annotation.Nullable; @@ -168,5 +169,11 @@ public class PassthroughBlockMaterial implements BlockMaterial { public CompoundTag getDefaultTile() { return blockMaterial.getDefaultTile(); } + + @Override + public @Nullable FaweCompoundTag defaultTile() { + return blockMaterial.defaultTile(); + } + //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java index 763ac81bc..737510816 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java @@ -19,8 +19,11 @@ package com.sk89q.worldedit.world.registry; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.jnbt.CompoundTag; +import javax.annotation.Nullable; + class SimpleBlockMaterial implements BlockMaterial { private boolean isAir; @@ -251,8 +254,12 @@ class SimpleBlockMaterial implements BlockMaterial { } @Override - public CompoundTag getDefaultTile() { - return tile; + public @Nullable FaweCompoundTag defaultTile() { + // this implementation is very lazy, but SimpleBlockMaterial isn't really used anyway + if (tile != null) { + return FaweCompoundTag.of(tile.toLinTag()); + } + return null; } //FAWE end From e8c7d67b5b960dcc1fe60c4e41104141905b6a40 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sat, 14 Sep 2024 10:48:59 +0200 Subject: [PATCH 376/466] Fix regen on modern versions (#2881) * work on regen * simplify * fix more regen * cleanup, backport * revert unneeded change --- .../fawe/v1_20_R2/regen/PaperweightRegen.java | 412 +++------------ .../fawe/v1_20_R3/regen/PaperweightRegen.java | 411 +++------------ .../fawe/v1_20_R4/regen/PaperweightRegen.java | 386 ++------------ .../fawe/v1_21_R1/PaperweightFaweAdapter.java | 3 +- .../fawe/v1_21_R1/regen/PaperweightRegen.java | 413 ++------------- .../bukkit/adapter/Regenerator.java | 496 +----------------- 6 files changed, 234 insertions(+), 1887 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/regen/PaperweightRegen.java index 2ec8e6e41..e892c6f7e 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/regen/PaperweightRegen.java @@ -4,167 +4,74 @@ import com.fastasyncworldedit.bukkit.adapter.Regenerator; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.queue.IChunkCache; import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.util.ReflectionUtils; -import com.fastasyncworldedit.core.util.TaskManager; +import com.fastasyncworldedit.core.queue.implementation.chunk.ChunkCache; import com.google.common.collect.ImmutableList; -import com.mojang.datafixers.util.Either; import com.mojang.serialization.Lifecycle; +import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.PaperweightGetBlocks; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.io.file.SafeFiles; import com.sk89q.worldedit.world.RegenOptions; -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message; -import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.progress.ChunkProgressListener; -import net.minecraft.util.thread.ProcessorHandle; -import net.minecraft.util.thread.ProcessorMailbox; +import net.minecraft.util.ProgressListener; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.LevelSettings; import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.BiomeSource; -import net.minecraft.world.level.biome.FixedBiomeSource; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkGenerator; -import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; -import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.levelgen.WorldOptions; -import net.minecraft.world.level.levelgen.blending.BlendingData; -import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; -import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PrimaryLevelData; -import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; -import org.bukkit.Chunk; +import org.bukkit.World; import org.bukkit.craftbukkit.v1_20_R2.CraftServer; import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R2.generator.CustomChunkGenerator; import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.lang.reflect.Field; import java.nio.file.Path; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import java.util.OptionalLong; -import java.util.Random; -import java.util.concurrent.CompletableFuture; import java.util.function.BooleanSupplier; import java.util.function.Supplier; import static net.minecraft.core.registries.Registries.BIOME; -public class PaperweightRegen extends Regenerator { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); +public class PaperweightRegen extends Regenerator { private static final Field serverWorldsField; private static final Field paperConfigField; - private static final Field flatBedrockField; - private static final Field generatorSettingFlatField; private static final Field generatorSettingBaseSupplierField; - private static final Field delegateField; - private static final Field chunkSourceField; - private static final Field generatorStructureStateField; - private static final Field ringPositionsField; - private static final Field hasGeneratedPositionsField; - //list of chunk stati in correct order without FULL - private static final Map chunkStati = new LinkedHashMap<>(); static { - chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing - chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps - chunkStati.put( - ChunkStatus.STRUCTURE_REFERENCES, - Concurrency.FULL - ); // structure refs: radius 8, but only writes to current chunk - chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // biomes: radius 0 - chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8 - chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE - chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results - /*chunkStati.put( - ChunkStatus.LIQUID_CARVERS, - Concurrency.NONE - ); // liquid carvers: radius 0, but RADIUS and FULL change results*/ - chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps - chunkStati.put( - ChunkStatus.LIGHT, - Concurrency.FULL - ); // light: radius 1, but no writes to other chunks, only current chunk - chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0 - // chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0 - try { serverWorldsField = CraftServer.class.getDeclaredField("worlds"); serverWorldsField.setAccessible(true); Field tmpPaperConfigField; - Field tmpFlatBedrockField; try { //only present on paper tmpPaperConfigField = Level.class.getDeclaredField("paperConfig"); tmpPaperConfigField.setAccessible(true); - - tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock"); - tmpFlatBedrockField.setAccessible(true); } catch (Exception e) { tmpPaperConfigField = null; - tmpFlatBedrockField = null; } paperConfigField = tmpPaperConfigField; - flatBedrockField = tmpFlatBedrockField; generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName( "settings", "e")); generatorSettingBaseSupplierField.setAccessible(true); - - generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "d")); - generatorSettingFlatField.setAccessible(true); - - delegateField = CustomChunkGenerator.class.getDeclaredField("delegate"); - delegateField.setAccessible(true); - - chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "I")); - chunkSourceField.setAccessible(true); - - generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "v")); - generatorStructureStateField.setAccessible(true); - - ringPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(Refraction.pickName("ringPositions", "g")); - ringPositionsField.setAccessible(true); - - hasGeneratedPositionsField = ChunkGeneratorStructureState.class.getDeclaredField( - Refraction.pickName("hasGeneratedPositions", "h") - ); - hasGeneratedPositionsField.setAccessible(true); } catch (Exception e) { throw new RuntimeException(e); } @@ -172,43 +79,37 @@ public class PaperweightRegen extends Regenerator super.chunkStatuses.put(new ChunkStatusWrap(s), c)); - return true; } @Override - @SuppressWarnings("unchecked") protected boolean initNewWorld() throws Exception { //world folder tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen"); @@ -254,8 +155,10 @@ public class PaperweightRegen extends Regenerator getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { + public @NotNull Holder getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { if (options.hasBiomeType()) { return singleBiome; } - return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome( - biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler() - ); + return super.getUncachedNoiseBiome(biomeX, biomeY, biomeZ); + } + + @Override + public void save( + @org.jetbrains.annotations.Nullable final ProgressListener progressListener, + final boolean flush, + final boolean savingDisabled + ) { + // noop, spigot + } + + @Override + public void save( + @Nullable final ProgressListener progressListener, + final boolean flush, + final boolean savingDisabled, + final boolean close + ) { + // noop, paper } }).get(); freshWorld.noSave = true; @@ -292,89 +208,6 @@ public class PaperweightRegen extends Regenerator generatorSettingBaseSupplier = (Holder) generatorSettingBaseSupplierField.get( - originalGenerator); - BiomeSource biomeSource; - if (options.hasBiomeType()) { - - biomeSource = new FixedBiomeSource( - DedicatedServer.getServer().registryAccess() - .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( - WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) - ) - ); - } else { - biomeSource = originalGenerator.getBiomeSource(); - } - chunkGenerator = new NoiseBasedChunkGenerator( - biomeSource, - generatorSettingBaseSupplier - ); - } else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) { - chunkGenerator = customChunkGenerator.getDelegate(); - } else { - LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName()); - return false; - } - if (generator != null) { - chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator); - generateConcurrent = generator.isParallelCapable(); - } -// chunkGenerator.conf = freshWorld.spigotConfig; - Does not exist anymore, may need to be re-addressed - - freshChunkProvider = new ServerChunkCache( - freshWorld, - session, - server.getFixerUpper(), - server.getStructureManager(), - server.executor, - chunkGenerator, - freshWorld.spigotConfig.viewDistance, - freshWorld.spigotConfig.simulationDistance, - server.forceSynchronousWrites(), - new RegenNoOpWorldLoadListener(), - (chunkCoordIntPair, state) -> { - }, - () -> server.overworld().getDataStorage() - ) { - // redirect to LevelChunks created in #createChunks - @Override - public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean create) { - ChunkAccess chunkAccess = getChunkAt(x, z); - if (chunkAccess == null && create) { - chunkAccess = createChunk(getProtoChunkAt(x, z)); - } - return chunkAccess; - } - }; - - if (seed == originalOpts.seed() && !options.hasBiomeType()) { - // Optimisation for needless ring position calculation when the seed and biome is the same. - ChunkGeneratorStructureState state = (ChunkGeneratorStructureState) generatorStructureStateField.get(originalChunkProvider.chunkMap); - boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(state); - if (hasGeneratedPositions) { - Map>> origPositions = - (Map>>) ringPositionsField.get(state); - Map>> copy = new Object2ObjectArrayMap<>( - origPositions); - ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get(freshChunkProvider.chunkMap); - ringPositionsField.set(newState, copy); - hasGeneratedPositionsField.setBoolean(newState, true); - } - } - - - chunkSourceField.set(freshWorld, freshChunkProvider); - //let's start then - structureTemplateManager = server.getStructureManager(); - threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider); - return true; } @@ -389,7 +222,8 @@ public class PaperweightRegen extends Regenerator { try { - freshChunkProvider.close(false); + freshWorld.getChunkSource().getDataStorage().cache.clear(); + freshWorld.getChunkSource().close(false); } catch (Exception e) { throw new RuntimeException(e); } @@ -410,63 +244,20 @@ public class PaperweightRegen extends Regenerator getBlockPopulators() { - return originalServerWorld.getWorld().getPopulators(); - } - - @Override - protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) { - // BlockPopulator#populate has to be called synchronously for TileEntity access - TaskManager.taskManager().task(() -> { - final CraftWorld world = freshWorld.getWorld(); - final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ); - blockPopulator.populate(world, random, chunk); - }); - } - @Override protected IChunkCache initSourceQueueCache() { - return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) { - @Override - public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) { - return getChunkAt(x, z); - } - }; + return new ChunkCache<>(BukkitAdapter.adapt(freshWorld.getWorld())); } //util @SuppressWarnings("unchecked") private void removeWorldFromWorldsMap() { - Fawe.instance().getQueueHandler().sync(() -> { - try { - Map map = (Map) serverWorldsField.get(Bukkit.getServer()); - map.remove("faweregentempworld"); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - }); + try { + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); + map.remove("faweregentempworld"); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } } private ResourceKey getWorldDimKey(org.bukkit.World.Environment env) { @@ -483,11 +274,15 @@ public class PaperweightRegen extends Regenerator biomeRegistry, - @Nullable final BlendingData blendingData - ) { - super(pos, upgradeData, world, biomeRegistry, blendingData); - } - - // avoid warning on paper - - // compatibility with spigot - - public boolean generateFlatBedrock() { - return generateFlatBedrock; - } - - // no one will ever see the entities! - @Override - public List getEntities() { - return Collections.emptyList(); - } - - } - - protected class ChunkStatusWrap extends ChunkStatusWrapper { - - private final ChunkStatus chunkStatus; - - public ChunkStatusWrap(ChunkStatus chunkStatus) { - this.chunkStatus = chunkStatus; - } - - @Override - public int requiredNeighborChunkRadius() { - return chunkStatus.getRange(); - } - - @Override - public String name() { - return chunkStatus.toString(); - } - - @Override - public CompletableFuture processChunk(List accessibleChunks) { - return chunkStatus.generate( - Runnable::run, // TODO revisit, we might profit from this somehow? - freshWorld, - chunkGenerator, - structureTemplateManager, - threadedLevelLightEngine, - c -> CompletableFuture.completedFuture(Either.left(c)), - accessibleChunks - ); - } - - } - - /** - * A light engine that does nothing. As light is calculated after pasting anyway, we can avoid - * work this way. - */ - static class NoOpLightEngine extends ThreadedLevelLightEngine { - - private static final ProcessorMailbox MAILBOX = ProcessorMailbox.create(task -> { - }, "fawe-no-op"); - private static final ProcessorHandle> HANDLE = ProcessorHandle.of("fawe-no-op", m -> { - }); - - public NoOpLightEngine(final ServerChunkCache chunkProvider) { - super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE); - } - - @Override - public CompletableFuture lightChunk(final ChunkAccess chunk, final boolean excludeBlocks) { - return CompletableFuture.completedFuture(chunk); - } - - } - } diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/regen/PaperweightRegen.java index edf9e9f90..cce14ee1c 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/regen/PaperweightRegen.java @@ -4,166 +4,74 @@ import com.fastasyncworldedit.bukkit.adapter.Regenerator; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.queue.IChunkCache; import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.util.TaskManager; +import com.fastasyncworldedit.core.queue.implementation.chunk.ChunkCache; import com.google.common.collect.ImmutableList; -import com.mojang.datafixers.util.Either; import com.mojang.serialization.Lifecycle; +import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.PaperweightGetBlocks; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.io.file.SafeFiles; import com.sk89q.worldedit.world.RegenOptions; -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message; -import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.progress.ChunkProgressListener; -import net.minecraft.util.thread.ProcessorHandle; -import net.minecraft.util.thread.ProcessorMailbox; +import net.minecraft.util.ProgressListener; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.LevelSettings; import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.BiomeSource; -import net.minecraft.world.level.biome.FixedBiomeSource; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkGenerator; -import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; -import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.levelgen.WorldOptions; -import net.minecraft.world.level.levelgen.blending.BlendingData; -import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; -import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PrimaryLevelData; -import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; -import org.bukkit.Chunk; +import org.bukkit.World; import org.bukkit.craftbukkit.v1_20_R3.CraftServer; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator; import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.lang.reflect.Field; import java.nio.file.Path; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import java.util.OptionalLong; -import java.util.Random; -import java.util.concurrent.CompletableFuture; import java.util.function.BooleanSupplier; import java.util.function.Supplier; import static net.minecraft.core.registries.Registries.BIOME; -public class PaperweightRegen extends Regenerator { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); +public class PaperweightRegen extends Regenerator { private static final Field serverWorldsField; private static final Field paperConfigField; - private static final Field flatBedrockField; - private static final Field generatorSettingFlatField; private static final Field generatorSettingBaseSupplierField; - private static final Field delegateField; - private static final Field chunkSourceField; - private static final Field generatorStructureStateField; - private static final Field ringPositionsField; - private static final Field hasGeneratedPositionsField; - //list of chunk stati in correct order without FULL - private static final Map chunkStati = new LinkedHashMap<>(); static { - chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing - chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps - chunkStati.put( - ChunkStatus.STRUCTURE_REFERENCES, - Concurrency.FULL - ); // structure refs: radius 8, but only writes to current chunk - chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // biomes: radius 0 - chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8 - chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE - chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results - /*chunkStati.put( - ChunkStatus.LIQUID_CARVERS, - Concurrency.NONE - ); // liquid carvers: radius 0, but RADIUS and FULL change results*/ - chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps - chunkStati.put( - ChunkStatus.LIGHT, - Concurrency.FULL - ); // light: radius 1, but no writes to other chunks, only current chunk - chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0 - // chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0 - try { serverWorldsField = CraftServer.class.getDeclaredField("worlds"); serverWorldsField.setAccessible(true); Field tmpPaperConfigField; - Field tmpFlatBedrockField; try { //only present on paper tmpPaperConfigField = Level.class.getDeclaredField("paperConfig"); tmpPaperConfigField.setAccessible(true); - - tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock"); - tmpFlatBedrockField.setAccessible(true); } catch (Exception e) { tmpPaperConfigField = null; - tmpFlatBedrockField = null; } paperConfigField = tmpPaperConfigField; - flatBedrockField = tmpFlatBedrockField; generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName( "settings", "e")); generatorSettingBaseSupplierField.setAccessible(true); - - generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "d")); - generatorSettingFlatField.setAccessible(true); - - delegateField = CustomChunkGenerator.class.getDeclaredField("delegate"); - delegateField.setAccessible(true); - - chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "I")); - chunkSourceField.setAccessible(true); - - generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "v")); - generatorStructureStateField.setAccessible(true); - - ringPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(Refraction.pickName("ringPositions", "g")); - ringPositionsField.setAccessible(true); - - hasGeneratedPositionsField = ChunkGeneratorStructureState.class.getDeclaredField( - Refraction.pickName("hasGeneratedPositions", "h") - ); - hasGeneratedPositionsField.setAccessible(true); } catch (Exception e) { throw new RuntimeException(e); } @@ -171,43 +79,37 @@ public class PaperweightRegen extends Regenerator super.chunkStatuses.put(new ChunkStatusWrap(s), c)); - return true; } @Override - @SuppressWarnings("unchecked") protected boolean initNewWorld() throws Exception { //world folder tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen"); @@ -253,8 +155,10 @@ public class PaperweightRegen extends Regenerator getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { + public @NotNull Holder getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { if (options.hasBiomeType()) { return singleBiome; } - return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome( - biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler() - ); + return super.getUncachedNoiseBiome(biomeX, biomeY, biomeZ); + } + + @Override + public void save( + @org.jetbrains.annotations.Nullable final ProgressListener progressListener, + final boolean flush, + final boolean savingDisabled + ) { + // noop, spigot + } + + @Override + public void save( + @Nullable final ProgressListener progressListener, + final boolean flush, + final boolean savingDisabled, + final boolean close + ) { + // noop, paper } }).get(); freshWorld.noSave = true; @@ -291,89 +208,6 @@ public class PaperweightRegen extends Regenerator generatorSettingBaseSupplier = (Holder) generatorSettingBaseSupplierField.get( - originalGenerator); - BiomeSource biomeSource; - if (options.hasBiomeType()) { - - biomeSource = new FixedBiomeSource( - DedicatedServer.getServer().registryAccess() - .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( - WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) - ) - ); - } else { - biomeSource = originalGenerator.getBiomeSource(); - } - chunkGenerator = new NoiseBasedChunkGenerator( - biomeSource, - generatorSettingBaseSupplier - ); - } else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) { - chunkGenerator = customChunkGenerator.getDelegate(); - } else { - LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName()); - return false; - } - if (generator != null) { - chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator); - generateConcurrent = generator.isParallelCapable(); - } -// chunkGenerator.conf = freshWorld.spigotConfig; - Does not exist anymore, may need to be re-addressed - - freshChunkProvider = new ServerChunkCache( - freshWorld, - session, - server.getFixerUpper(), - server.getStructureManager(), - server.executor, - chunkGenerator, - freshWorld.spigotConfig.viewDistance, - freshWorld.spigotConfig.simulationDistance, - server.forceSynchronousWrites(), - new RegenNoOpWorldLoadListener(), - (chunkCoordIntPair, state) -> { - }, - () -> server.overworld().getDataStorage() - ) { - // redirect to LevelChunks created in #createChunks - @Override - public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean create) { - ChunkAccess chunkAccess = getChunkAt(x, z); - if (chunkAccess == null && create) { - chunkAccess = createChunk(getProtoChunkAt(x, z)); - } - return chunkAccess; - } - }; - - if (seed == originalOpts.seed() && !options.hasBiomeType()) { - // Optimisation for needless ring position calculation when the seed and biome is the same. - ChunkGeneratorStructureState state = (ChunkGeneratorStructureState) generatorStructureStateField.get(originalChunkProvider.chunkMap); - boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(state); - if (hasGeneratedPositions) { - Map>> origPositions = - (Map>>) ringPositionsField.get(state); - Map>> copy = new Object2ObjectArrayMap<>( - origPositions); - ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get(freshChunkProvider.chunkMap); - ringPositionsField.set(newState, copy); - hasGeneratedPositionsField.setBoolean(newState, true); - } - } - - - chunkSourceField.set(freshWorld, freshChunkProvider); - //let's start then - structureTemplateManager = server.getStructureManager(); - threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider); - return true; } @@ -388,7 +222,8 @@ public class PaperweightRegen extends Regenerator { try { - freshChunkProvider.close(false); + freshWorld.getChunkSource().getDataStorage().cache.clear(); + freshWorld.getChunkSource().close(false); } catch (Exception e) { throw new RuntimeException(e); } @@ -409,63 +244,20 @@ public class PaperweightRegen extends Regenerator getBlockPopulators() { - return originalServerWorld.getWorld().getPopulators(); - } - - @Override - protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) { - // BlockPopulator#populate has to be called synchronously for TileEntity access - TaskManager.taskManager().task(() -> { - final CraftWorld world = freshWorld.getWorld(); - final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ); - blockPopulator.populate(world, random, chunk); - }); - } - @Override protected IChunkCache initSourceQueueCache() { - return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) { - @Override - public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) { - return getChunkAt(x, z); - } - }; + return new ChunkCache<>(BukkitAdapter.adapt(freshWorld.getWorld())); } //util @SuppressWarnings("unchecked") private void removeWorldFromWorldsMap() { - Fawe.instance().getQueueHandler().sync(() -> { - try { - Map map = (Map) serverWorldsField.get(Bukkit.getServer()); - map.remove("faweregentempworld"); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - }); + try { + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); + map.remove("faweregentempworld"); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } } private ResourceKey getWorldDimKey(org.bukkit.World.Environment env) { @@ -482,11 +274,15 @@ public class PaperweightRegen extends Regenerator biomeRegistry, - @Nullable final BlendingData blendingData - ) { - super(pos, upgradeData, world, biomeRegistry, blendingData); - } - - // avoid warning on paper - - // compatibility with spigot - - public boolean generateFlatBedrock() { - return generateFlatBedrock; - } - - // no one will ever see the entities! - @Override - public List getEntities() { - return Collections.emptyList(); - } - - } - - protected class ChunkStatusWrap extends ChunkStatusWrapper { - - private final ChunkStatus chunkStatus; - - public ChunkStatusWrap(ChunkStatus chunkStatus) { - this.chunkStatus = chunkStatus; - } - - @Override - public int requiredNeighborChunkRadius() { - return chunkStatus.getRange(); - } - - @Override - public String name() { - return chunkStatus.toString(); - } - - @Override - public CompletableFuture processChunk(List accessibleChunks) { - return chunkStatus.generate( - Runnable::run, // TODO revisit, we might profit from this somehow? - freshWorld, - chunkGenerator, - structureTemplateManager, - threadedLevelLightEngine, - c -> CompletableFuture.completedFuture(Either.left(c)), - accessibleChunks - ); - } - - } - - /** - * A light engine that does nothing. As light is calculated after pasting anyway, we can avoid - * work this way. - */ - static class NoOpLightEngine extends ThreadedLevelLightEngine { - - private static final ProcessorMailbox MAILBOX = ProcessorMailbox.create(task -> { - }, "fawe-no-op"); - private static final ProcessorHandle> HANDLE = ProcessorHandle.of("fawe-no-op", m -> { - }); - - public NoOpLightEngine(final ServerChunkCache chunkProvider) { - super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE); - } - - @Override - public CompletableFuture lightChunk(final ChunkAccess chunk, final boolean excludeBlocks) { - return CompletableFuture.completedFuture(chunk); - } - - } - } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/regen/PaperweightRegen.java index e21e7eef7..d80d098ff 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/regen/PaperweightRegen.java @@ -4,166 +4,73 @@ import com.fastasyncworldedit.bukkit.adapter.Regenerator; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.queue.IChunkCache; import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.util.TaskManager; +import com.fastasyncworldedit.core.queue.implementation.chunk.ChunkCache; import com.google.common.collect.ImmutableList; import com.mojang.serialization.Lifecycle; +import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.PaperweightGetBlocks; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.io.file.SafeFiles; import com.sk89q.worldedit.world.RegenOptions; -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message; -import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.progress.ChunkProgressListener; -import net.minecraft.util.thread.ProcessorHandle; -import net.minecraft.util.thread.ProcessorMailbox; +import net.minecraft.util.ProgressListener; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.LevelSettings; import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.BiomeSource; -import net.minecraft.world.level.biome.FixedBiomeSource; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkGenerator; -import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.status.ChunkStatus; -import net.minecraft.world.level.chunk.status.WorldGenContext; import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; -import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.levelgen.WorldOptions; -import net.minecraft.world.level.levelgen.blending.BlendingData; -import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; -import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PrimaryLevelData; -import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; -import org.bukkit.Chunk; +import org.bukkit.World; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.lang.reflect.Field; import java.nio.file.Path; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import java.util.OptionalLong; -import java.util.Random; -import java.util.concurrent.CompletableFuture; import java.util.function.BooleanSupplier; import java.util.function.Supplier; import static net.minecraft.core.registries.Registries.BIOME; -public class PaperweightRegen extends Regenerator { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); +public class PaperweightRegen extends Regenerator { private static final Field serverWorldsField; private static final Field paperConfigField; - private static final Field flatBedrockField; - private static final Field generatorSettingFlatField; private static final Field generatorSettingBaseSupplierField; - private static final Field delegateField; - private static final Field chunkSourceField; - private static final Field generatorStructureStateField; - private static final Field ringPositionsField; - private static final Field hasGeneratedPositionsField; - //list of chunk stati in correct order without FULL - private static final Map chunkStati = new LinkedHashMap<>(); static { - chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing - chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps - chunkStati.put( - ChunkStatus.STRUCTURE_REFERENCES, - Concurrency.NONE - ); // structure refs: radius 8, but only writes to current chunk - chunkStati.put(ChunkStatus.BIOMES, Concurrency.NONE); // biomes: radius 0 - chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8 - chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE - chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results - chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps - chunkStati.put( - ChunkStatus.INITIALIZE_LIGHT, - Concurrency.FULL - ); // initialize_light: radius 0 - chunkStati.put( - ChunkStatus.LIGHT, - Concurrency.FULL - ); // light: radius 1, but no writes to other chunks, only current chunk - chunkStati.put(ChunkStatus.SPAWN, Concurrency.NONE); // spawn: radius 0 - try { serverWorldsField = CraftServer.class.getDeclaredField("worlds"); serverWorldsField.setAccessible(true); Field tmpPaperConfigField; - Field tmpFlatBedrockField; try { //only present on paper tmpPaperConfigField = Level.class.getDeclaredField("paperConfig"); tmpPaperConfigField.setAccessible(true); - - tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock"); - tmpFlatBedrockField.setAccessible(true); } catch (Exception e) { tmpPaperConfigField = null; - tmpFlatBedrockField = null; } paperConfigField = tmpPaperConfigField; - flatBedrockField = tmpFlatBedrockField; generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName( "settings", "e")); generatorSettingBaseSupplierField.setAccessible(true); - - generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "d")); - generatorSettingFlatField.setAccessible(true); - - delegateField = CustomChunkGenerator.class.getDeclaredField("delegate"); - delegateField.setAccessible(true); - - chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "I")); - chunkSourceField.setAccessible(true); - - generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "v")); - generatorStructureStateField.setAccessible(true); - - ringPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(Refraction.pickName("ringPositions", "g")); - ringPositionsField.setAccessible(true); - - hasGeneratedPositionsField = ChunkGeneratorStructureState.class.getDeclaredField( - Refraction.pickName("hasGeneratedPositions", "h") - ); - hasGeneratedPositionsField.setAccessible(true); } catch (Exception e) { throw new RuntimeException(e); } @@ -171,44 +78,37 @@ public class PaperweightRegen extends Regenerator super.chunkStatuses.put(new ChunkStatusWrap(s), c)); - return true; } @Override - @SuppressWarnings("unchecked") protected boolean initNewWorld() throws Exception { //world folder tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen"); @@ -254,8 +154,10 @@ public class PaperweightRegen extends Regenerator getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { if (options.hasBiomeType()) { return singleBiome; } - return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome( - biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler() - ); + return super.getUncachedNoiseBiome(biomeX, biomeY, biomeZ); } + @Override + public void save( + @org.jetbrains.annotations.Nullable final ProgressListener progressListener, + final boolean flush, + final boolean savingDisabled + ) { + // noop, spigot + } + + @Override + public void save( + @Nullable final ProgressListener progressListener, + final boolean flush, + final boolean savingDisabled, + final boolean close + ) { + // noop, paper + } }).get(); freshWorld.noSave = true; removeWorldFromWorldsMap(); @@ -293,93 +207,6 @@ public class PaperweightRegen extends Regenerator generatorSettingBaseSupplier = (Holder) - generatorSettingBaseSupplierField.get(noiseBasedChunkGenerator); - BiomeSource biomeSource; - if (options.hasBiomeType()) { - biomeSource = new FixedBiomeSource( - DedicatedServer.getServer().registryAccess() - .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( - WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) - ) - ); - } else { - biomeSource = originalGenerator.getBiomeSource(); - } - chunkGenerator = new NoiseBasedChunkGenerator( - biomeSource, - generatorSettingBaseSupplier - ); - } else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) { - chunkGenerator = customChunkGenerator.getDelegate(); - } else { - LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName()); - return false; - } - if (generator != null) { - chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator); - generateConcurrent = generator.isParallelCapable(); - } -// chunkGenerator.conf = freshWorld.spigotConfig; - Does not exist anymore, may need to be re-addressed - - freshChunkProvider = new ServerChunkCache( - freshWorld, - session, - server.getFixerUpper(), - server.getStructureManager(), - server.executor, - chunkGenerator, - freshWorld.spigotConfig.viewDistance, - freshWorld.spigotConfig.simulationDistance, - server.forceSynchronousWrites(), - new RegenNoOpWorldLoadListener(), - (chunkCoordIntPair, state) -> { - }, - () -> server.overworld().getDataStorage() - ) { - // redirect to LevelChunks created in #createChunks - @Override - public ChunkAccess getChunk(int x, int z, @NotNull ChunkStatus chunkstatus, boolean create) { - ChunkAccess chunkAccess = getChunkAt(x, z); - if (chunkAccess == null && create) { - chunkAccess = createChunk(getProtoChunkAt(x, z)); - } - return chunkAccess; - } - }; - - if (seed == originalOpts.seed() && !options.hasBiomeType()) { - // Optimisation for needless ring position calculation when the seed and biome is the same. - ChunkGeneratorStructureState state = (ChunkGeneratorStructureState) generatorStructureStateField.get( - originalChunkProvider.chunkMap); - boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(state); - if (hasGeneratedPositions) { - Map>> origPositions = - (Map>>) ringPositionsField.get(state); - Map>> copy = new Object2ObjectArrayMap<>( - origPositions); - ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get( - freshChunkProvider.chunkMap); - ringPositionsField.set(newState, copy); - hasGeneratedPositionsField.setBoolean(newState, true); - } - } - - - chunkSourceField.set(freshWorld, freshChunkProvider); - //let's start then - structureTemplateManager = server.getStructureManager(); - threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider); - - this.worldGenContext = new WorldGenContext(freshWorld, chunkGenerator, structureTemplateManager, - threadedLevelLightEngine - ); return true; } @@ -394,7 +221,8 @@ public class PaperweightRegen extends Regenerator { try { - freshChunkProvider.close(false); + freshWorld.getChunkSource().getDataStorage().cache.clear(); + freshWorld.getChunkSource().close(false); } catch (Exception e) { throw new RuntimeException(e); } @@ -415,50 +243,9 @@ public class PaperweightRegen extends Regenerator getBlockPopulators() { - return originalServerWorld.getWorld().getPopulators(); - } - - @Override - protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) { - // BlockPopulator#populate has to be called synchronously for TileEntity access - TaskManager.taskManager().task(() -> { - final CraftWorld world = freshWorld.getWorld(); - final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ); - blockPopulator.populate(world, random, chunk); - }); - } - @Override protected IChunkCache initSourceQueueCache() { - return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) { - @Override - public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) { - return getChunkAt(x, z); - } - }; + return new ChunkCache<>(BukkitAdapter.adapt(freshWorld.getWorld())); } //util @@ -512,83 +299,4 @@ public class PaperweightRegen extends Regenerator biomeRegistry, - @Nullable final BlendingData blendingData - ) { - super(pos, upgradeData, world, biomeRegistry, blendingData); - } - - // avoid warning on paper - - @SuppressWarnings("unused") // compatibility with spigot - public boolean generateFlatBedrock() { - return generateFlatBedrock; - } - - // no one will ever see the entities! - @Override - public @NotNull List getEntities() { - return Collections.emptyList(); - } - - } - - protected class ChunkStatusWrap extends ChunkStatusWrapper { - - private final ChunkStatus chunkStatus; - - public ChunkStatusWrap(ChunkStatus chunkStatus) { - this.chunkStatus = chunkStatus; - } - - @Override - public int requiredNeighborChunkRadius() { - return chunkStatus.getRange(); - } - - @Override - public String name() { - return chunkStatus.toString(); - } - - @Override - public CompletableFuture processChunk(List accessibleChunks) { - return chunkStatus.generate( - worldGenContext, - Runnable::run, - CompletableFuture::completedFuture, - accessibleChunks - ); - } - - } - - /** - * A light engine that does nothing. As light is calculated after pasting anyway, we can avoid - * work this way. - */ - static class NoOpLightEngine extends ThreadedLevelLightEngine { - - private static final ProcessorMailbox MAILBOX = ProcessorMailbox.create(task -> { - }, "fawe-no-op"); - private static final ProcessorHandle> HANDLE = ProcessorHandle.of("fawe-no-op", m -> { - }); - - public NoOpLightEngine(final ServerChunkCache chunkProvider) { - super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE); - } - - @Override - public @NotNull CompletableFuture lightChunk(final @NotNull ChunkAccess chunk, final boolean excludeBlocks) { - return CompletableFuture.completedFuture(chunk); - } - - } - } diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java index 9452024c5..34fc70f8d 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java @@ -19,6 +19,7 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.regen.PaperweightRegen; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.internal.block.BlockStateIdAccess; @@ -565,7 +566,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); +public class PaperweightRegen extends Regenerator { private static final Field serverWorldsField; private static final Field paperConfigField; - private static final Field flatBedrockField; - private static final Field generatorSettingFlatField; private static final Field generatorSettingBaseSupplierField; - private static final Field delegateField; - private static final Field chunkSourceField; - private static final Field generatorStructureStateField; - private static final Field ringPositionsField; - private static final Field hasGeneratedPositionsField; - //list of chunk stati in correct order without FULL - private static final Map chunkStati = new LinkedHashMap<>(); static { - chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing - chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps - chunkStati.put( - ChunkStatus.STRUCTURE_REFERENCES, - Concurrency.NONE - ); // structure refs: radius 8, but only writes to current chunk - chunkStati.put(ChunkStatus.BIOMES, Concurrency.NONE); // biomes: radius 0 - chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8 - chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE - chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results - chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps - chunkStati.put( - ChunkStatus.INITIALIZE_LIGHT, - Concurrency.FULL - ); // initialize_light: radius 0 - chunkStati.put( - ChunkStatus.LIGHT, - Concurrency.FULL - ); // light: radius 1, but no writes to other chunks, only current chunk - chunkStati.put(ChunkStatus.SPAWN, Concurrency.NONE); // spawn: radius 0 - try { serverWorldsField = CraftServer.class.getDeclaredField("worlds"); serverWorldsField.setAccessible(true); Field tmpPaperConfigField; - Field tmpFlatBedrockField; try { //only present on paper tmpPaperConfigField = Level.class.getDeclaredField("paperConfig"); tmpPaperConfigField.setAccessible(true); - - tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock"); - tmpFlatBedrockField.setAccessible(true); } catch (Exception e) { tmpPaperConfigField = null; - tmpFlatBedrockField = null; } paperConfigField = tmpPaperConfigField; - flatBedrockField = tmpFlatBedrockField; generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName( "settings", "e")); generatorSettingBaseSupplierField.setAccessible(true); - - generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "d")); - generatorSettingFlatField.setAccessible(true); - - delegateField = CustomChunkGenerator.class.getDeclaredField("delegate"); - delegateField.setAccessible(true); - - chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "I")); - chunkSourceField.setAccessible(true); - - generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "w")); - generatorStructureStateField.setAccessible(true); - - ringPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(Refraction.pickName("ringPositions", "g")); - ringPositionsField.setAccessible(true); - - hasGeneratedPositionsField = ChunkGeneratorStructureState.class.getDeclaredField( - Refraction.pickName("hasGeneratedPositions", "h") - ); - hasGeneratedPositionsField.setAccessible(true); } catch (Exception e) { throw new RuntimeException(e); } @@ -177,47 +78,37 @@ public class PaperweightRegen extends Regenerator super.chunkStatuses.put(new ChunkStatusWrap(s), c)); - return true; } @Override - @SuppressWarnings("unchecked") protected boolean initNewWorld() throws Exception { //world folder tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen"); @@ -263,8 +154,10 @@ public class PaperweightRegen extends Regenerator getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { if (options.hasBiomeType()) { return singleBiome; } - return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome( - biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler() - ); + return super.getUncachedNoiseBiome(biomeX, biomeY, biomeZ); } + @Override + public void save( + @Nullable final ProgressListener progressListener, + final boolean flush, + final boolean savingDisabled + ) { + // noop, spigot + } + + @Override + public void save( + @Nullable final ProgressListener progressListener, + final boolean flush, + final boolean savingDisabled, + final boolean close + ) { + // noop, paper + } }).get(); freshWorld.noSave = true; removeWorldFromWorldsMap(); @@ -302,97 +207,6 @@ public class PaperweightRegen extends Regenerator generatorSettingBaseSupplier = (Holder) - generatorSettingBaseSupplierField.get(noiseBasedChunkGenerator); - BiomeSource biomeSource; - if (options.hasBiomeType()) { - biomeSource = new FixedBiomeSource( - DedicatedServer.getServer().registryAccess() - .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( - WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) - ) - ); - } else { - biomeSource = originalGenerator.getBiomeSource(); - } - chunkGenerator = new NoiseBasedChunkGenerator( - biomeSource, - generatorSettingBaseSupplier - ); - } else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) { - chunkGenerator = customChunkGenerator.getDelegate(); - } else { - LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName()); - return false; - } - if (generator != null) { - chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator); - generateConcurrent = generator.isParallelCapable(); - } -// chunkGenerator.conf = freshWorld.spigotConfig; - Does not exist anymore, may need to be re-addressed - - freshChunkProvider = new ServerChunkCache( - freshWorld, - session, - server.getFixerUpper(), - server.getStructureManager(), - server.executor, - chunkGenerator, - freshWorld.spigotConfig.viewDistance, - freshWorld.spigotConfig.simulationDistance, - server.forceSynchronousWrites(), - new RegenNoOpWorldLoadListener(), - (chunkCoordIntPair, state) -> { - }, - () -> server.overworld().getDataStorage() - ) { - // redirect to LevelChunks created in #createChunks - @Override - public ChunkAccess getChunk(int x, int z, @NotNull ChunkStatus chunkstatus, boolean create) { - ChunkAccess chunkAccess = getChunkAt(x, z); - if (chunkAccess == null && create) { - chunkAccess = createChunk(getProtoChunkAt(x, z)); - } - return chunkAccess; - } - }; - - if (seed == originalOpts.seed() && !options.hasBiomeType()) { - // Optimisation for needless ring position calculation when the seed and biome is the same. - ChunkGeneratorStructureState state = (ChunkGeneratorStructureState) generatorStructureStateField.get( - originalChunkProvider.chunkMap); - boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(state); - if (hasGeneratedPositions) { - Map>> origPositions = - (Map>>) ringPositionsField.get(state); - Map>> copy = new Object2ObjectArrayMap<>( - origPositions); - ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get( - freshChunkProvider.chunkMap); - ringPositionsField.set(newState, copy); - hasGeneratedPositionsField.setBoolean(newState, true); - } - } - - - chunkSourceField.set(freshWorld, freshChunkProvider); - //let's start then - structureTemplateManager = server.getStructureManager(); - threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider); - - this.worldGenContext = new WorldGenContext( - freshWorld, - chunkGenerator, - structureTemplateManager, - threadedLevelLightEngine, - originalChunkProvider.chunkMap.worldGenContext.mainThreadMailBox() - ); return true; } @@ -407,7 +221,8 @@ public class PaperweightRegen extends Regenerator { try { - freshChunkProvider.close(false); + freshWorld.getChunkSource().getDataStorage().cache.clear(); + freshWorld.getChunkSource().close(false); } catch (Exception e) { throw new RuntimeException(e); } @@ -428,50 +243,9 @@ public class PaperweightRegen extends Regenerator getBlockPopulators() { - return originalServerWorld.getWorld().getPopulators(); - } - - @Override - protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) { - // BlockPopulator#populate has to be called synchronously for TileEntity access - TaskManager.taskManager().task(() -> { - final CraftWorld world = freshWorld.getWorld(); - final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ); - blockPopulator.populate(world, random, chunk); - }); - } - @Override protected IChunkCache initSourceQueueCache() { - return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) { - @Override - public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) { - return getChunkAt(x, z); - } - }; + return new ChunkCache<>(BukkitAdapter.adapt(freshWorld.getWorld())); } //util @@ -525,99 +299,4 @@ public class PaperweightRegen extends Regenerator biomeRegistry, - @Nullable final BlendingData blendingData - ) { - super(pos, upgradeData, world, biomeRegistry, blendingData); - } - - // avoid warning on paper - - @SuppressWarnings("unused") // compatibility with spigot - public boolean generateFlatBedrock() { - return generateFlatBedrock; - } - - // no one will ever see the entities! - @Override - public @NotNull List getEntities() { - return Collections.emptyList(); - } - - } - - protected class ChunkStatusWrap extends ChunkStatusWrapper { - - private final ChunkStatus chunkStatus; - - public ChunkStatusWrap(ChunkStatus chunkStatus) { - this.chunkStatus = chunkStatus; - } - - @Override - public int requiredNeighborChunkRadius() { - return ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.FULL).getAccumulatedRadiusOf(chunkStatus); - } - - @Override - public String name() { - return chunkStatus.toString(); - } - - @Override - public CompletableFuture processChunk(List accessibleChunks) { - ChunkAccess chunkAccess = accessibleChunks.get(accessibleChunks.size() / 2); - int chunkX = chunkAccess.getPos().x; - int chunkZ = chunkAccess.getPos().z; - getProtoChunkAt(chunkX, chunkZ); - StaticCache2D neighbours = StaticCache2D - .create( - chunkX, - chunkZ, - requiredNeighborChunkRadius(), - (final int nx, final int nz) -> new ChunkHolder(new ChunkPos(nx, nz), - ChunkHolderManager.MAX_TICKET_LEVEL, - freshWorld, - threadedLevelLightEngine, - null, - freshChunkProvider.chunkMap - ) - ); - return ChunkPyramid.GENERATION_PYRAMID.getStepTo(chunkStatus).apply( - worldGenContext, - neighbours, - chunkAccess - ); - } - - } - - /** - * A light engine that does nothing. As light is calculated after pasting anyway, we can avoid - * work this way. - */ - static class NoOpLightEngine extends ThreadedLevelLightEngine { - - private static final ProcessorMailbox MAILBOX = ProcessorMailbox.create(task -> { - }, "fawe-no-op"); - private static final ProcessorHandle> HANDLE = ProcessorHandle.of("fawe-no-op", m -> { - }); - - public NoOpLightEngine(final ServerChunkCache chunkProvider) { - super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE); - } - - @Override - public @NotNull CompletableFuture lightChunk(final @NotNull ChunkAccess chunk, final boolean excludeBlocks) { - return CompletableFuture.completedFuture(chunk); - } - - } - } diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java index 4afbe03a2..ac75a29f6 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java @@ -1,67 +1,32 @@ package com.fastasyncworldedit.bukkit.adapter; -import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.queue.IChunkCache; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.SingleThreadQueueExtent; -import com.fastasyncworldedit.core.util.MathMan; -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.fastasyncworldedit.core.util.TaskManager; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.longs.LongArrayList; -import it.unimi.dsi.fastutil.longs.LongList; -import jdk.jfr.Category; -import jdk.jfr.Event; -import jdk.jfr.Label; -import jdk.jfr.Name; -import org.apache.logging.log4j.Logger; import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.WorldInfo; -import java.util.AbstractList; -import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Random; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.function.BooleanSupplier; import java.util.function.Function; /** * Represents an abstract regeneration handler. - * - * @param the type of the {@code IChunkAccess} of the current Minecraft implementation - * @param the type of the {@code ProtoChunk} of the current Minecraft implementation - * @param the type of the {@code Chunk} of the current Minecraft implementation - * @param the type of the {@code ChunkStatusWrapper} wrapping the {@code ChunkStatus} enum */ -public abstract class Regenerator> { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); +public abstract class Regenerator { protected final org.bukkit.World originalBukkitWorld; protected final Region region; @@ -69,13 +34,8 @@ public abstract class Regenerator chunkStatuses = new LinkedHashMap<>(); // TODO (j21): use SequencedMap - private final Long2ObjectLinkedOpenHashMap protoChunks = new Long2ObjectLinkedOpenHashMap<>(); - private final Long2ObjectOpenHashMap chunks = new Long2ObjectOpenHashMap<>(); - protected boolean generateConcurrent = true; protected long seed; - private ExecutorService executor; - private SingleThreadQueueExtent source; + protected SingleThreadQueueExtent source; /** * Initializes an abstract regeneration handler. @@ -92,15 +52,6 @@ public abstract class Regenerator chunkCoordsForChunkStatus = new LinkedHashMap<>(); - int borderSum = 1; - // TODO (j21): use SequencedMap#sequencedKeySet().reversed() - final List reversedKeys = Lists.reverse(new ArrayList<>(chunkStatuses.keySet())); - for (final ChunkStatus status : reversedKeys) { - chunkCoordsForChunkStatus.put(status, getChunkCoordsRegen(region, borderSum)); - borderSum += status.requiredNeighborChunkRadius(); - } - - //create chunks - // TODO (j21): use SequencedMap#firstEntry().getKey() - for (long xz : chunkCoordsForChunkStatus.get(chunkStatuses.keySet().iterator().next())) { - ProtoChunk chunk = createProtoChunk(MathMan.unpairIntX(xz), MathMan.unpairIntY(xz)); - protoChunks.put(xz, chunk); - } - - // a memory-efficient, lightweight "list" that calculates index -> ChunkAccess - // as needed when accessed - class LazyChunkList extends AbstractList { - private final int size; - private final int minX; - private final int minZ; - private final int sizeSqrt; - - LazyChunkList(int radius, int centerX, int centerZ) { - this.sizeSqrt = radius + 1 + radius; // length of one side - this.size = this.sizeSqrt * this.sizeSqrt; - this.minX = centerX - radius; - this.minZ = centerZ - radius; - } - @Override - public IChunkAccess get(final int index) { - Objects.checkIndex(index, size); - int absX = (index % sizeSqrt) + minX; - int absZ = (index / sizeSqrt) + minZ; - return protoChunks.get(MathMan.pairInt(absX, absZ)); - } - - @Override - public int size() { - return size; - } - - } - @Label("Regeneration") - @Category("FAWE") - @Name("fawe.regen") - class RegenerationEvent extends Event { - private String chunkStatus; - private int chunksToProcess; - } - - //run generation tasks excluding FULL chunk status - for (Map.Entry entry : chunkStatuses.entrySet()) { - ChunkStatus chunkStatus = entry.getKey(); - final RegenerationEvent event = new RegenerationEvent(); - event.begin(); - event.chunkStatus = chunkStatus.name(); - int radius = Math.max(1, chunkStatus.requiredNeighborChunkRadius0()); - - long[] coords = chunkCoordsForChunkStatus.get(chunkStatus); - event.chunksToProcess = coords.length; - if (this.generateConcurrent && entry.getValue() == Concurrency.RADIUS) { - SequentialTasks> tasks = getChunkStatusTaskRows(coords, radius); - for (ConcurrentTasks para : tasks) { - List scheduled = new ArrayList<>(tasks.size()); - for (LongList row : para) { - scheduled.add(() -> { - for (long xz : row) { - chunkStatus.processChunkSave(xz, new LazyChunkList(radius, MathMan.unpairIntX(xz), - MathMan.unpairIntY(xz))); - } - }); - } - runAndWait(scheduled); - } - } else if (this.generateConcurrent && entry.getValue() == Concurrency.FULL) { - // every chunk can be processed individually - List scheduled = new ArrayList<>(coords.length); - for (long xz : coords) { - scheduled.add(() -> chunkStatus.processChunkSave(xz, new LazyChunkList(radius, MathMan.unpairIntX(xz), - MathMan.unpairIntY(xz)))); - } - runAndWait(scheduled); - } else { // Concurrency.NONE or generateConcurrent == false - // run sequential but submit to different thread - // running regen on the main thread otherwise triggers async-only events on the main thread - executor.submit(() -> { - for (long xz : coords) { - chunkStatus.processChunkSave(xz, new LazyChunkList(radius, MathMan.unpairIntX(xz), - MathMan.unpairIntY(xz))); - } - }).get(); // wait until finished this step - } - event.commit(); - } - - //convert to proper chunks - // TODO (j21): use SequencedMap#firstEntry().getValue() - for (long xz : chunkCoordsForChunkStatus.values().iterator().next()) { - ProtoChunk proto = protoChunks.get(xz); - chunks.put(xz, createChunk(proto)); - } - - //final chunkstatus - ChunkStatus FULL = getFullChunkStatus(); - // TODO (j21): use SequencedMap#firstEntry().getValue() - for (long xz : chunkCoordsForChunkStatus.values().iterator().next()) { //FULL.requiredNeighbourChunkRadius() == 0! - Chunk chunk = chunks.get(xz); - FULL.processChunkSave(xz, List.of(chunk)); - } - - //populate - List populators = getBlockPopulators(); - // TODO (j21): use SequencedMap#firstEntry().getValue() - for (long xz : chunkCoordsForChunkStatus.values().iterator().next()) { - int x = MathMan.unpairIntX(xz); - int z = MathMan.unpairIntY(xz); - - //prepare chunk seed - Random random = getChunkRandom(seed, x, z); - - //actually populate - Chunk c = chunks.get(xz); - populators.forEach(pop -> { - populate(c, random, pop); - }); - } + private void createSource() { source = new SingleThreadQueueExtent( BukkitWorld.HAS_MIN_Y ? originalBukkitWorld.getMinHeight() : 0, BukkitWorld.HAS_MIN_Y ? originalBukkitWorld.getMaxHeight() : 256 ); source.init(target, initSourceQueueCache(), null); - return true; - } - - private void runAndWait(final List tasks) { - try { - List> futures = new ArrayList<>(); - tasks.forEach(task -> futures.add(executor.submit(task))); - for (Future future : futures) { - future.get(); - } - } catch (Exception e) { - LOGGER.catching(e); - } } private void copyToWorld() { + createSource(); + final long timeoutPerTick = TimeUnit.MILLISECONDS.toNanos(10); + int taskId = TaskManager.taskManager().repeat(() -> { + final long startTime = System.nanoTime(); + runTasks(() -> System.nanoTime() - startTime < timeoutPerTick); + }, 1); //Setting Blocks boolean genbiomes = options.shouldRegenBiomes(); boolean hasBiome = options.hasBiomeType(); @@ -343,6 +117,7 @@ public abstract class Regenerator source.getBiome(vec))); } + TaskManager.taskManager().cancel(taskId); } private class PlacementPattern implements Pattern { @@ -382,9 +157,6 @@ public abstract class Regenerator getBlockPopulators(); - - /** - * Implement the population of the {@code Chunk} with the given chunk random and {@code BlockPopulator} here. - * - * @param chunk the {@code Chunk} to populate - * @param random the chunk random to use for population - * @param pop the {@code BlockPopulator} to use - */ - protected abstract void populate(Chunk chunk, Random random, BlockPopulator pop); - /** * Implement the initialization an {@code IChunkCache} here. Use will need the {@code getChunkAt} function * @@ -464,106 +195,6 @@ public abstract class Regenerator initSourceQueueCache(); - //algorithms - private long[] getChunkCoordsRegen(Region region, int border) { //needs to be square num of chunks - BlockVector3 oldMin = region.getMinimumPoint(); - BlockVector3 newMin = BlockVector3.at( - (oldMin.x() >> 4 << 4) - border * 16, - oldMin.y(), - (oldMin.z() >> 4 << 4) - border * 16 - ); - BlockVector3 oldMax = region.getMaximumPoint(); - BlockVector3 newMax = BlockVector3.at( - (oldMax.x() >> 4 << 4) + (border + 1) * 16 - 1, - oldMax.y(), - (oldMax.z() >> 4 << 4) + (border + 1) * 16 - 1 - ); - Region adjustedRegion = new CuboidRegion(newMin, newMax); - return adjustedRegion.getChunks().stream() - .sorted(Comparator - .comparingInt(BlockVector2::z) - .thenComparingInt(BlockVector2::x)) //needed for RegionLimitedWorldAccess - .mapToLong(c -> MathMan.pairInt(c.x(), c.z())) - .toArray(); - } - - /** - * Creates a list of chunkcoord rows that may be executed concurrently - * - * @param allCoords the coords that should be sorted into rows, must be sorted by z and x - * @param requiredNeighborChunkRadius the radius of neighbor chunks that may not be written to concurrently (ChunkStatus - * .requiredNeighborRadius) - * @return a list of chunkcoords rows that may be executed concurrently - */ - private SequentialTasks> getChunkStatusTaskRows( - long[] allCoords, - int requiredNeighborChunkRadius - ) { - int requiredNeighbors = Math.max(0, requiredNeighborChunkRadius); - - final int coordsCount = allCoords.length; - long first = coordsCount == 0 ? 0 : allCoords[0]; - long last = coordsCount == 0 ? 0 : allCoords[coordsCount - 1]; - int minX = MathMan.unpairIntX(first); - int maxX = MathMan.unpairIntX(last); - int minZ = MathMan.unpairIntY(first); - int maxZ = MathMan.unpairIntY(last); - SequentialTasks> tasks; - if (maxZ - minZ > maxX - minX) { - int numlists = Math.min(requiredNeighbors * 2 + 1, maxX - minX + 1); - - Int2ObjectOpenHashMap byX = new Int2ObjectOpenHashMap<>(); - int expectedListLength = (coordsCount + 1) / (maxX - minX); - - //init lists - for (int i = minX; i <= maxX; i++) { - byX.put(i, new LongArrayList(expectedListLength)); - } - - //sort into lists by x coord - for (long allCoord : allCoords) { - byX.get(MathMan.unpairIntX(allCoord)).add(allCoord); - } - - //create parallel tasks - tasks = new SequentialTasks<>(numlists); - for (int offset = 0; offset < numlists; offset++) { - ConcurrentTasks para = new ConcurrentTasks<>((maxZ - minZ + 1) / numlists + 1); - for (int i = 0; minX + i * numlists + offset <= maxX; i++) { - para.add(byX.get(minX + i * numlists + offset)); - } - tasks.add(para); - } - } else { - int numlists = Math.min(requiredNeighbors * 2 + 1, maxZ - minZ + 1); - - Int2ObjectOpenHashMap byZ = new Int2ObjectOpenHashMap<>(); - int expectedListLength = (coordsCount + 1) / (maxZ - minZ + 2); - - //init lists - for (int i = minZ; i <= maxZ; i++) { - byZ.put(i, new LongArrayList(expectedListLength)); - } - - //sort into lists by x coord - for (long allCoord : allCoords) { - byZ.get(MathMan.unpairIntY(allCoord)).add(allCoord); - } - - //create parallel tasks - tasks = new SequentialTasks<>(numlists); - for (int offset = 0; offset < numlists; offset++) { - ConcurrentTasks para = new ConcurrentTasks<>((maxX - minX + 1) / numlists + 1); - for (int i = 0; minZ + i * numlists + offset <= maxZ; i++) { - para.add(byZ.get(minZ + i * numlists + offset)); - } - tasks.add(para); - } - } - - return tasks; - } - protected BiomeProvider getBiomeProvider() { if (options.hasBiomeType()) { return new SingleBiomeProvider(); @@ -579,103 +210,6 @@ public abstract class Regenerator the IChunkAccess class of the current Minecraft implementation - */ - public static abstract class ChunkStatusWrapper { - - /** - * Return the required neighbor chunk radius the wrapped {@code ChunkStatus} requires. - * - * @return the radius of required neighbor chunks - */ - public abstract int requiredNeighborChunkRadius(); - - int requiredNeighborChunkRadius0() { - return Math.max(0, requiredNeighborChunkRadius()); - } - - /** - * Return the name of the wrapped {@code ChunkStatus}. - * - * @return the radius of required neighbor chunks - */ - public abstract String name(); - - /** - * Return the name of the wrapped {@code ChunkStatus}. - * - * @param accessibleChunks a list of chunks that will be used during the execution of the wrapped {@code ChunkStatus}. - * This list is order in the correct order required by the {@code ChunkStatus}, unless Mojang suddenly decides to do things differently. - */ - public abstract CompletableFuture processChunk(List accessibleChunks); - - void processChunkSave(long xz, List accessibleChunks) { - try { - processChunk(accessibleChunks).get(); - } catch (Exception e) { - LOGGER.error("Error while running {} on chunk {}/{}", - name(), MathMan.unpairIntX(xz), MathMan.unpairIntY(xz), e); - } - } - - @Override - public String toString() { - return name(); - } - - } - - public static class SequentialTasks extends Tasks { - - public SequentialTasks(int expectedSize) { - super(expectedSize); - } - - } - - public static class ConcurrentTasks extends Tasks { - - public ConcurrentTasks(int expectedSize) { - super(expectedSize); - } - - } - - public static class Tasks implements Iterable { - - private final List tasks; - - public Tasks(int expectedSize) { - tasks = new ArrayList<>(expectedSize); - } - - public void add(T task) { - tasks.add(task); - } - - public List list() { - return tasks; - } - - public int size() { - return tasks.size(); - } - - @Override - public Iterator iterator() { - return tasks.iterator(); - } - - @Override - public String toString() { - return tasks.toString(); - } - - } - public class SingleBiomeProvider extends BiomeProvider { private final org.bukkit.block.Biome biome = BukkitAdapter.adapt(options.getBiomeType()); From f820cb2fb4cf982c27a919d7b173668857964a9e Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 15 Sep 2024 14:34:04 +0200 Subject: [PATCH 377/466] Update javadoc url of paper 1.21.1 Signed-off-by: Alexander Brandes --- buildSrc/src/main/kotlin/CommonJavaConfig.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/CommonJavaConfig.kt b/buildSrc/src/main/kotlin/CommonJavaConfig.kt index d221a98d2..155321fbc 100644 --- a/buildSrc/src/main/kotlin/CommonJavaConfig.kt +++ b/buildSrc/src/main/kotlin/CommonJavaConfig.kt @@ -61,7 +61,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean "https://jd.advntr.dev/api/latest/", "https://logging.apache.org/log4j/2.x/javadoc/log4j-api/", "https://www.antlr.org/api/Java/", - "https://jd.papermc.io/paper/1.21/", + "https://jd.papermc.io/paper/1.21.1/", "https://intellectualsites.github.io/fastasyncworldedit-javadocs/worldedit-core/" ) docTitle = "${rootProject.name}-${project.description}" + " " + "${rootProject.version}" From 49b063a1879e749035dacf801f19de15dcd118dc Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 15 Sep 2024 16:00:17 +0100 Subject: [PATCH 378/466] fix: compound tags can be nullable when converting state to baseblock (#2914) --- .../core/extent/filter/block/CharFilterBlock.java | 3 +-- .../com/fastasyncworldedit/core/world/block/CompoundInput.java | 3 +-- .../com/sk89q/worldedit/extent/AbstractDelegateExtent.java | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java index b1862987f..74571af05 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java @@ -263,8 +263,7 @@ public class CharFilterBlock extends ChunkFilterBlock { final BlockMaterial material = state.getMaterial(); if (material.hasContainer()) { final FaweCompoundTag tag = get.tile(x, y + yy, z); - assert tag != null : "has container but is null"; - return state.toBaseBlock(tag.linTag()); + return state.toBaseBlock(tag == null ? null : tag.linTag()); } return state.toBaseBlock(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/block/CompoundInput.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/block/CompoundInput.java index 481f8d54f..eff3c3de6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/block/CompoundInput.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/block/CompoundInput.java @@ -17,8 +17,7 @@ public enum CompoundInput { @Override public BaseBlock get(final BlockState state, final IBlocks blocks, final int x, final int y, final int z) { final FaweCompoundTag tile = blocks.tile(x, y, z); - assert tile != null : "container without tile entity"; - return state.toBaseBlock(tile.linTag()); + return state.toBaseBlock(tile == null ? null : tile.linTag()); } }; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java index 267734247..89c450a10 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -427,7 +427,7 @@ public class AbstractDelegateExtent implements Extent { @Override public boolean tile(int x, int y, int z, FaweCompoundTag tile) throws WorldEditException { - return setBlock(x, y, z, getBlock(x, y, z).toBaseBlock(tile.linTag())); + return setBlock(x, y, z, getBlock(x, y, z).toBaseBlock(tile == null ? null : tile.linTag())); } //FAWE end From ea5589b1f031f2135a1c4d22018c347560edaddb Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sun, 15 Sep 2024 17:00:56 +0200 Subject: [PATCH 379/466] Introduce basic support for Vector API (#2890) * Introduce basic support for Vector API * add modules to javadoc too * add assumption comments --- build.gradle.kts | 2 +- buildSrc/src/main/kotlin/CommonJavaConfig.kt | 3 + .../core/configuration/Settings.java | 5 + .../core/extent/filter/CountFilter.java | 10 +- .../core/extent/filter/LinkedFilter.java | 36 ++++++- .../core/extent/filter/MaskFilter.java | 52 +++++++++- .../extent/filter/block/CharFilterBlock.java | 15 +-- .../core/internal/simd/SimdSupport.java | 99 +++++++++++++++++++ .../simd/VectorizedCharFilterBlock.java | 33 +++++++ .../core/internal/simd/VectorizedFilter.java | 8 ++ .../core/internal/simd/VectorizedMask.java | 40 ++++++++ .../core/queue/IQueueExtent.java | 9 +- .../implementation/ParallelQueueExtent.java | 6 +- .../sk89q/worldedit/extent/MaskingExtent.java | 22 ++++- .../sk89q/worldedit/function/mask/Mask.java | 18 ++++ 15 files changed, 341 insertions(+), 17 deletions(-) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/SimdSupport.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedCharFilterBlock.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedFilter.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedMask.java diff --git a/build.gradle.kts b/build.gradle.kts index 5c8ce8016..afe45594c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -91,7 +91,7 @@ tasks { minecraftVersion(it) pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile } .toTypedArray()) - jvmArgs("-DPaper.IgnoreJavaVersion=true", "-Dcom.mojang.eula.agree=true") + jvmArgs("-DPaper.IgnoreJavaVersion=true", "-Dcom.mojang.eula.agree=true", "--add-modules=jdk.incubator.vector") group = "run paper" runDirectory.set(file("run-$it")) } diff --git a/buildSrc/src/main/kotlin/CommonJavaConfig.kt b/buildSrc/src/main/kotlin/CommonJavaConfig.kt index 155321fbc..ea921709c 100644 --- a/buildSrc/src/main/kotlin/CommonJavaConfig.kt +++ b/buildSrc/src/main/kotlin/CommonJavaConfig.kt @@ -28,6 +28,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean options.isDeprecation = true options.encoding = "UTF-8" options.compilerArgs.add("-parameters") + options.compilerArgs.add("--add-modules=jdk.incubator.vector") } configurations.all { @@ -51,12 +52,14 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean tasks.withType().configureEach { (options as StandardJavadocDocletOptions).apply { addStringOption("Xdoclint:none", "-quiet") + addStringOption("-add-modules", "jdk.incubator.vector") tags( "apiNote:a:API Note:", "implSpec:a:Implementation Requirements:", "implNote:a:Implementation Note:" ) options.encoding = "UTF-8" + links( "https://jd.advntr.dev/api/latest/", "https://logging.apache.org/log4j/2.x/javadoc/log4j-api/", diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index 4db469187..d35219bec 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -675,6 +675,11 @@ public class Settings extends Config { }) public boolean ALLOW_TICK_FLUIDS = false; + @Comment({ + "Whether FAWE should use the incubator Vector API to accelerate some operations" + }) + public boolean USE_VECTOR_API = false; + } @Comment({"Web/HTTP connection related settings"}) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/CountFilter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/CountFilter.java index 72ee73013..f6844e684 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/CountFilter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/CountFilter.java @@ -1,8 +1,10 @@ package com.fastasyncworldedit.core.extent.filter; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; +import com.fastasyncworldedit.core.internal.simd.VectorizedFilter; +import jdk.incubator.vector.ShortVector; -public class CountFilter extends ForkedFilter { +public class CountFilter extends ForkedFilter implements VectorizedFilter { private int total; @@ -33,4 +35,10 @@ public class CountFilter extends ForkedFilter { return total; } + @Override + public ShortVector applyVector(final ShortVector get, final ShortVector set) { + total += set.length(); + return set; + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/LinkedFilter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/LinkedFilter.java index 25627c451..a600fc180 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/LinkedFilter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/LinkedFilter.java @@ -2,7 +2,9 @@ package com.fastasyncworldedit.core.extent.filter; import com.fastasyncworldedit.core.extent.filter.block.DelegateFilter; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; +import com.fastasyncworldedit.core.internal.simd.VectorizedFilter; import com.fastasyncworldedit.core.queue.Filter; +import jdk.incubator.vector.ShortVector; /** * Filter which links two Filters together for single-filter-input operations. @@ -10,10 +12,18 @@ import com.fastasyncworldedit.core.queue.Filter; * @param Parent which extends Filter * @param Child which extends Filter */ -public final class LinkedFilter extends DelegateFilter { +public sealed class LinkedFilter extends DelegateFilter { private final S child; + @SuppressWarnings({"unchecked", "rawtypes"}) // we defeated the type system + public static LinkedFilter of(T parent, S child) { + if (parent instanceof VectorizedFilter p && child instanceof VectorizedFilter c) { + return new VectorizedLinkedFilter(p, c); + } + return new LinkedFilter<>(parent, child); + } + public LinkedFilter(T parent, S child) { super(parent); this.child = child; @@ -30,8 +40,30 @@ public final class LinkedFilter extends Dele } @Override - public LinkedFilter, Filter> newInstance(Filter other) { + public LinkedFilter, ? extends Filter> newInstance(Filter other) { return new LinkedFilter<>(this, other); } + private final static class VectorizedLinkedFilter + extends LinkedFilter implements VectorizedFilter { + + public VectorizedLinkedFilter(final T parent, final S child) { + super(parent, child); + } + + @Override + public ShortVector applyVector(final ShortVector get, final ShortVector set) { + ShortVector res = getParent().applyVector(get, set); + return getChild().applyVector(get, res); + } + + @Override + public LinkedFilter, Filter> newInstance(Filter other) { + if (other instanceof VectorizedFilter o) { + return new VectorizedLinkedFilter(this, o); + } + return new LinkedFilter<>(this, other); + } + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/MaskFilter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/MaskFilter.java index 9284f8378..ac31938e2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/MaskFilter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/MaskFilter.java @@ -2,10 +2,17 @@ package com.fastasyncworldedit.core.extent.filter; import com.fastasyncworldedit.core.extent.filter.block.DelegateFilter; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; +import com.fastasyncworldedit.core.internal.simd.SimdSupport; +import com.fastasyncworldedit.core.internal.simd.VectorizedFilter; +import com.fastasyncworldedit.core.internal.simd.VectorizedMask; import com.fastasyncworldedit.core.queue.Filter; import com.sk89q.worldedit.function.mask.AbstractExtentMask; import com.sk89q.worldedit.function.mask.Mask; +import jdk.incubator.vector.ShortVector; +import jdk.incubator.vector.VectorMask; +import jdk.incubator.vector.VectorOperators; +import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; /** @@ -15,8 +22,8 @@ import java.util.concurrent.atomic.AtomicInteger; */ public class MaskFilter extends DelegateFilter { - private final Mask mask; - private final AtomicInteger changes; + final Mask mask; + final AtomicInteger changes; public MaskFilter(T other, Mask root) { this(other, root, new AtomicInteger()); @@ -60,4 +67,45 @@ public class MaskFilter extends DelegateFilter { return new MaskFilter<>(getParent().fork(), mask.copy(), changes); } + public static class VectorizedMaskFilter extends MaskFilter implements VectorizedFilter { + + private final VectorizedMask vectorizedMask; + + public VectorizedMaskFilter(final T other, final Mask root) { + super(other, root); + this.vectorizedMask = Objects.requireNonNull(SimdSupport.vectorizedTargetMask(root), "invalid vectorizable mask"); + } + + public VectorizedMaskFilter(final T other, final Mask root, AtomicInteger changes) { + super(other, root, changes); + this.vectorizedMask = Objects.requireNonNull(SimdSupport.vectorizedTargetMask(root), "invalid vectorizable mask"); + } + + @Override + public ShortVector applyVector(final ShortVector get, final ShortVector set) { + final T parent = getParent(); + VectorMask masked = vectorizedMask.compareVector(set, get); + ShortVector res = parent.applyVector(get, set); + res = set.blend(res, masked); + VectorMask changed = res.compare(VectorOperators.NE, set); + changes.getAndAdd(changed.trueCount()); + return res; + } + + @Override + public MaskFilter newInstance(final Filter other) { + if (other instanceof VectorizedFilter o) { + return new VectorizedMaskFilter<>(o, mask); + } + return super.newInstance(other); + } + + @SuppressWarnings("unchecked") + @Override + public Filter fork() { + return new VectorizedMaskFilter<>((T) getParent().fork(), mask.copy(), changes); + } + + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java index 74571af05..cafd4513a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java @@ -23,12 +23,14 @@ import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.registry.BlockMaterial; import org.enginehub.linbus.tree.LinCompoundTag; +import org.jetbrains.annotations.ApiStatus; import javax.annotation.Nonnull; import javax.annotation.Nullable; import static com.sk89q.worldedit.world.block.BlockTypesCache.states; +@ApiStatus.NonExtendable public class CharFilterBlock extends ChunkFilterBlock { private static final SetDelegate FULL = (block, value) -> block.setArr[block.index] = value; @@ -38,10 +40,10 @@ public class CharFilterBlock extends ChunkFilterBlock { private int minLayer; private CharGetBlocks get; private IChunkSet set; - private char[] getArr; + protected char[] getArr; @Nullable - private char[] setArr; - private SetDelegate delegate; + protected char[] setArr; + protected SetDelegate delegate; // local private int layer; private int index; @@ -172,7 +174,7 @@ public class CharFilterBlock extends ChunkFilterBlock { } @Override - public synchronized final void filter(Filter filter) { + public synchronized void filter(Filter filter) { for (y = 0, index = 0; y < 16; y++) { for (z = 0; z < 16; z++) { for (x = 0; x < 16; x++, index++) { @@ -395,7 +397,7 @@ public class CharFilterBlock extends ChunkFilterBlock { } //Set delegate - private SetDelegate initSet() { + protected final SetDelegate initSet() { setArr = set.load(layer); return delegate = FULL; } @@ -427,7 +429,8 @@ public class CharFilterBlock extends ChunkFilterBlock { return getExtent().setBiome(x, y, z, biome); } - private interface SetDelegate { + @ApiStatus.Internal + protected interface SetDelegate { void set(@Nonnull CharFilterBlock block, char value); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/SimdSupport.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/SimdSupport.java new file mode 100644 index 000000000..23d135fa6 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/SimdSupport.java @@ -0,0 +1,99 @@ +package com.fastasyncworldedit.core.internal.simd; + +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.extent.filter.block.DelegateFilter; +import com.fastasyncworldedit.core.function.mask.SingleBlockStateMask; +import com.fastasyncworldedit.core.queue.Filter; +import com.sk89q.worldedit.function.mask.InverseSingleBlockStateMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import jdk.incubator.vector.ShortVector; +import jdk.incubator.vector.VectorOperators; + +import javax.annotation.Nullable; + +public class SimdSupport { + + private static final boolean VECTOR_API_PRESENT; + + static { + boolean vectorApiPresent = false; + try { + Class.forName("jdk.incubator.vector.Vector"); + vectorApiPresent = true; + } catch (ClassNotFoundException ignored) { + } + VECTOR_API_PRESENT = vectorApiPresent; + if (!VECTOR_API_PRESENT && Settings.settings().EXPERIMENTAL.USE_VECTOR_API) { + LogManagerCompat.getLogger() + .warn("FAWE use-vector-api is enabled but --add-modules=jdk.incubator.vector is not set."); + } + } + + public static boolean useVectorApi() { + return VECTOR_API_PRESENT && Settings.settings().EXPERIMENTAL.USE_VECTOR_API; + } + + public static @Nullable VectorizedMask vectorizedTargetMask(Mask mask) { + if (!useVectorApi()) { + return null; + } + return switch (mask) { + case SingleBlockStateMask single -> vectorizedTargetMask(single.getBlockState().getOrdinalChar()); + case InverseSingleBlockStateMask inverse -> vectorizedTargetMaskInverse(inverse.getBlockState().getOrdinalChar()); + default -> null; + }; + } + + private static VectorizedMask vectorizedTargetMask(char ordinal) { + return (set, get) -> get.compare(VectorOperators.EQ, (short) ordinal); + } + + private static VectorizedMask vectorizedTargetMaskInverse(char ordinal) { + return (set, get) -> get.compare(VectorOperators.NE, (short) ordinal); + } + + public static @Nullable VectorizedFilter vectorizedPattern(Pattern pattern) { + if (!useVectorApi()) { + return null; + } + return switch (pattern) { + case BaseBlock block -> { + if (block.getNbtReference() == null) { + yield new VectorizedPattern<>(block, block.getOrdinalChar()); + } + yield null; + } + case BlockStateHolder blockStateHolder -> new VectorizedPattern<>( + blockStateHolder, + blockStateHolder.getOrdinalChar() + ); + default -> null; + }; + } + + private static final class VectorizedPattern extends DelegateFilter implements VectorizedFilter { + + private final char ordinal; + + public VectorizedPattern(final T parent, char ordinal) { + super(parent); + this.ordinal = ordinal; + } + + @Override + public ShortVector applyVector(final ShortVector get, final ShortVector set) { + return ShortVector.broadcast(ShortVector.SPECIES_PREFERRED, ordinal); + } + + @Override + public Filter newInstance(final Filter other) { + return new VectorizedPattern<>(other, ordinal); + } + + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedCharFilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedCharFilterBlock.java new file mode 100644 index 000000000..5c15da22a --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedCharFilterBlock.java @@ -0,0 +1,33 @@ +package com.fastasyncworldedit.core.internal.simd; + +import com.fastasyncworldedit.core.extent.filter.block.CharFilterBlock; +import com.fastasyncworldedit.core.queue.Filter; +import com.sk89q.worldedit.extent.Extent; +import jdk.incubator.vector.ShortVector; +import jdk.incubator.vector.VectorSpecies; + +public class VectorizedCharFilterBlock extends CharFilterBlock { + + public VectorizedCharFilterBlock(final Extent extent) { + super(extent); + } + + @Override + public synchronized void filter(final Filter filter) { + if (!(filter instanceof VectorizedFilter vecFilter)) { + throw new IllegalStateException("Unexpected VectorizedCharFilterBlock " + filter); + } + final VectorSpecies species = ShortVector.SPECIES_PREFERRED; + initSet(); // set array is null before + char[] setArr = this.setArr; + assert setArr != null; + char[] getArr = this.getArr; + // assume setArr.length == getArr.length == 4096 + for (int i = 0; i < 4096; i += species.length()) { + ShortVector set = ShortVector.fromCharArray(species, setArr, i); + ShortVector get = ShortVector.fromCharArray(species, getArr, i); + ShortVector res = vecFilter.applyVector(get, set); + res.intoCharArray(setArr, i); + } + } +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedFilter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedFilter.java new file mode 100644 index 000000000..7357bbd59 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedFilter.java @@ -0,0 +1,8 @@ +package com.fastasyncworldedit.core.internal.simd; + +import com.fastasyncworldedit.core.queue.Filter; +import jdk.incubator.vector.ShortVector; + +public interface VectorizedFilter extends Filter { + ShortVector applyVector(ShortVector get, ShortVector set); +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedMask.java new file mode 100644 index 000000000..0f453f32b --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedMask.java @@ -0,0 +1,40 @@ +package com.fastasyncworldedit.core.internal.simd; + +import com.fastasyncworldedit.core.queue.IChunk; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import jdk.incubator.vector.ShortVector; +import jdk.incubator.vector.VectorMask; +import jdk.incubator.vector.VectorSpecies; + +public interface VectorizedMask { + + default void processChunks(IChunk chunk, IChunkGet get, IChunkSet set) { + for (int layer = get.getMinSectionPosition(); layer <= get.getMaxSectionPosition(); layer++) { + final char[] sectionSet = set.loadIfPresent(layer); + if (sectionSet == null) { + continue; + } + final char[] sectionGet = get.load(layer); + processSection(layer, sectionSet, sectionGet); + } + } + + default void processSection(int layer, char[] set, char[] get) { + final VectorSpecies species = ShortVector.SPECIES_PREFERRED; + // assume that set.length % species.elementSize() == 0 + for (int i = 0; i < set.length; i += species.length()) { + ShortVector vectorSet = ShortVector.fromCharArray(species, set, i); + ShortVector vectorGet = ShortVector.fromCharArray(species, get, i); + vectorSet = processVector(vectorSet, vectorGet); + vectorSet.intoCharArray(set, i); + } + } + + default ShortVector processVector(ShortVector set, ShortVector get) { + return set.blend(0, compareVector(set, get).not()); + } + + VectorMask compareVector(ShortVector set, ShortVector get); + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java index 3f104b35d..ee3740411 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java @@ -2,6 +2,9 @@ package com.fastasyncworldedit.core.queue; import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock; import com.fastasyncworldedit.core.extent.processor.IBatchProcessorHolder; +import com.fastasyncworldedit.core.internal.simd.SimdSupport; +import com.fastasyncworldedit.core.internal.simd.VectorizedCharFilterBlock; +import com.fastasyncworldedit.core.internal.simd.VectorizedFilter; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.math.BlockVector2; @@ -146,7 +149,11 @@ public interface IQueueExtent extends Flushable, Trimable, ICh if (newChunk != null) { chunk = newChunk; if (block == null) { - block = this.createFilterBlock(); + if (SimdSupport.useVectorApi() && filter instanceof VectorizedFilter) { + block = new VectorizedCharFilterBlock(this); + } else { + block = this.createFilterBlock(); + } } block.initChunk(chunkX, chunkZ); chunk.filterBlocks(filter, block, region, full); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java index 1b56afdbc..f197524f3 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java @@ -14,6 +14,8 @@ import com.fastasyncworldedit.core.extent.processor.BatchProcessorHolder; import com.fastasyncworldedit.core.extent.processor.MultiBatchProcessor; import com.fastasyncworldedit.core.function.mask.BlockMaskBuilder; import com.fastasyncworldedit.core.internal.exception.FaweException; +import com.fastasyncworldedit.core.internal.simd.SimdSupport; +import com.fastasyncworldedit.core.internal.simd.VectorizedFilter; import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; @@ -223,7 +225,9 @@ public class ParallelQueueExtent extends PassthroughExtent { @Override public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException { - return this.changes = apply(region, new LinkedFilter<>(pattern, new CountFilter()), true).getChild().getTotal(); + VectorizedFilter vectorizedPattern = SimdSupport.vectorizedPattern(pattern); + var filter = LinkedFilter.of(vectorizedPattern == null ? pattern : vectorizedPattern, new CountFilter()); + return this.changes = apply(region, filter, true).getChild().getTotal(); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java index 0abc80153..77f9aa1c7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java @@ -24,6 +24,8 @@ import com.fastasyncworldedit.core.extent.filter.block.CharFilterBlock; import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; import com.fastasyncworldedit.core.extent.processor.ProcessorScope; +import com.fastasyncworldedit.core.internal.simd.SimdSupport; +import com.fastasyncworldedit.core.internal.simd.VectorizedMask; import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunk; @@ -35,6 +37,7 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; +import javax.annotation.Nullable; import java.util.function.LongFunction; import static com.google.common.base.Preconditions.checkNotNull; @@ -47,6 +50,7 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce //FAWE start private final LongFunction getOrCreateFilterBlock; private Mask mask; + private @Nullable VectorizedMask vectorizedMask; //FAWE end /** @@ -59,16 +63,23 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce super(extent); checkNotNull(mask); this.mask = mask; + this.vectorizedMask = SimdSupport.vectorizedTargetMask(mask); //FAWE start this.getOrCreateFilterBlock = FaweCache.INSTANCE.createMainThreadSafeCache(() -> new CharFilterBlock(getExtent())); //FAWE end } //FAWE start - private MaskingExtent(Extent extent, Mask mask, LongFunction getOrCreateFilterBlock) { + private MaskingExtent( + Extent extent, + Mask mask, + LongFunction getOrCreateFilterBlock, + @Nullable VectorizedMask vectorizedMask + ) { super(extent); checkNotNull(mask); this.mask = mask; + this.vectorizedMask = vectorizedMask; this.getOrCreateFilterBlock = getOrCreateFilterBlock; } //FAWE end @@ -90,6 +101,7 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce public void setMask(Mask mask) { checkNotNull(mask); this.mask = mask; + this.vectorizedMask = SimdSupport.vectorizedTargetMask(mask); } //FAWE start @@ -105,6 +117,10 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce @Override public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) { + if (this.vectorizedMask != null) { + this.vectorizedMask.processChunks(chunk, get, set); + return set; + } final ChunkFilterBlock filter = getOrCreateFilterBlock.apply(Thread.currentThread().getId()); filter.initChunk(chunk.getX(), chunk.getZ()); return filter.filter(chunk, get, set, this); @@ -122,12 +138,12 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce if (child == getExtent()) { return this; } - return new MaskingExtent(child, this.mask.copy(), this.getOrCreateFilterBlock); + return new MaskingExtent(child, this.mask.copy(), this.getOrCreateFilterBlock, this.vectorizedMask); } @Override public Filter fork() { - return new MaskingExtent(getExtent(), this.mask.copy(), this.getOrCreateFilterBlock); + return new MaskingExtent(getExtent(), this.mask.copy(), this.getOrCreateFilterBlock, this.vectorizedMask); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java index 94141278d..85e85a8c2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java @@ -22,7 +22,11 @@ package com.sk89q.worldedit.function.mask; import com.fastasyncworldedit.core.extent.filter.MaskFilter; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; import com.fastasyncworldedit.core.function.mask.InverseMask; +import com.fastasyncworldedit.core.internal.simd.SimdSupport; +import com.fastasyncworldedit.core.internal.simd.VectorizedFilter; +import com.fastasyncworldedit.core.internal.simd.VectorizedMask; import com.fastasyncworldedit.core.queue.Filter; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import javax.annotation.Nullable; @@ -64,7 +68,21 @@ public interface Mask { return null; } + @SuppressWarnings({"unchecked", "rawtypes"}) default MaskFilter toFilter(T filter) { + final VectorizedMask mask = SimdSupport.vectorizedTargetMask(this); + if (mask != null) { + VectorizedFilter vectorizedFilter = null; + if (filter instanceof VectorizedFilter vf) { + vectorizedFilter = vf; + } else if (filter instanceof Pattern p) { + vectorizedFilter = SimdSupport.vectorizedPattern(p); + } + if (vectorizedFilter != null) { + // also pass original? + return new MaskFilter.VectorizedMaskFilter(vectorizedFilter, this); + } + } return new MaskFilter<>(filter, this); } From 5ef7461b503665df310a6d04a9fd8fee4c2e0d15 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 15 Sep 2024 17:20:01 +0200 Subject: [PATCH 380/466] Release 2.11.2 Signed-off-by: Alexander Brandes --- .../core/history/change/ChangePopulator.java | 2 +- .../history/changeset/AbstractChangeSet.java | 18 +++++++++--------- .../changeset/ChangeExchangeCoordinator.java | 2 +- .../core/nbt/FaweCompoundTag.java | 2 +- .../fastasyncworldedit/core/queue/IBlocks.java | 6 +++--- .../core/queue/IChunkGet.java | 4 ++-- .../core/queue/IChunkSet.java | 4 ++-- .../core/queue/ITileInput.java | 2 +- .../fastasyncworldedit/core/util/MainUtil.java | 4 ++-- .../fastasyncworldedit/core/util/NbtUtils.java | 10 +++++----- .../core/world/block/CompoundInput.java | 2 +- .../src/main/java/com/sk89q/jnbt/NBTUtils.java | 2 +- .../sk89q/worldedit/extent/OutputExtent.java | 4 ++-- .../extent/clipboard/BlockArrayClipboard.java | 2 +- .../com/sk89q/worldedit/math/BlockVector3.java | 2 +- .../world/registry/BlockMaterial.java | 2 +- 16 files changed, 34 insertions(+), 34 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/ChangePopulator.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/ChangePopulator.java index 6831a443c..84424d948 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/ChangePopulator.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/ChangePopulator.java @@ -7,7 +7,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** - * @since TODO + * @since 2.11.2 */ @ApiStatus.Internal public interface ChangePopulator { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java index 3e60cb4eb..33931aac6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java @@ -242,7 +242,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { return ProcessorScope.READING_SET_BLOCKS; } - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") public void addTileCreate(CompoundTag tag) { addTileCreate(adapt(tag)); } @@ -256,11 +256,11 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { * Creates a tile/block entity create change to this change set. * * @param tag the tile/block entity to add. - * @since TODO + * @since 2.11.2 */ public abstract void addTileCreate(FaweCompoundTag tag); - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") public void addTileRemove(CompoundTag tag) { addTileRemove(adapt(tag)); } @@ -269,11 +269,11 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { * Creates a tile/block entity remove change to this change set. * * @param tag the tile/block entity to remove. - * @since TODO + * @since 2.11.2 */ public abstract void addTileRemove(FaweCompoundTag tag); - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") public void addEntityRemove(CompoundTag tag) { addEntityRemove(adapt(tag)); } @@ -282,11 +282,11 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { * Creates an entity remove change to this change set. * * @param tag the entity to remove. - * @since TODO + * @since 2.11.2 */ public abstract void addEntityRemove(FaweCompoundTag tag); - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") public void addEntityCreate(CompoundTag tag) { addEntityCreate(adapt(tag)); } @@ -295,7 +295,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { * Creates an entity create change to this change set. * * @param tag the entity to add. - * @since TODO + * @since 2.11.2 */ public abstract void addEntityCreate(FaweCompoundTag tag); @@ -307,7 +307,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { /** * {@return a coordinator to exchange sets of changes between a producer and a consumer} - * @since TODO + * @since 2.11.2 */ @ApiStatus.Internal public abstract ChangeExchangeCoordinator getCoordinatedChanges(BlockBag blockBag, int mode, boolean dir); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/ChangeExchangeCoordinator.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/ChangeExchangeCoordinator.java index 56d47500f..2f3398a60 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/ChangeExchangeCoordinator.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/ChangeExchangeCoordinator.java @@ -7,7 +7,7 @@ import java.util.concurrent.Exchanger; import java.util.function.BiConsumer; /** - * @since TODO + * @since 2.11.2 */ @ApiStatus.Internal public class ChangeExchangeCoordinator implements AutoCloseable { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/nbt/FaweCompoundTag.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/nbt/FaweCompoundTag.java index a244f7964..52e38908d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/nbt/FaweCompoundTag.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/nbt/FaweCompoundTag.java @@ -7,7 +7,7 @@ import org.enginehub.linbus.tree.LinCompoundTag; /** * A wrapper around compound tags, potentially lazily transformed. - * @since TODO + * @since 2.11.2 */ public sealed interface FaweCompoundTag permits EagerFaweCompoundTag, LazyFaweCompoundTag { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java index b14b7b39d..bda12dbe3 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java @@ -59,14 +59,14 @@ public interface IBlocks extends Trimable { BlockState getBlock(int x, int y, int z); - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") default Map getTiles() { return AdaptedMap.immutable(tiles(), pos -> pos, IBlocks::toCompoundTag); } Map tiles(); - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") default CompoundTag getTile(int x, int y, int z) { final FaweCompoundTag tile = tile(x, y, z); if (tile == null) { @@ -83,7 +83,7 @@ public interface IBlocks extends Trimable { @Nullable FaweCompoundTag tile(int x, int y, int z); - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") default Set getEntities() { return entities().stream() .map(IBlocks::toCompoundTag) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java index 1ead25284..b72690029 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkGet.java @@ -47,7 +47,7 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent, ITileInput { > T call(IChunkSet set, Runnable finalize); - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") default CompoundTag getEntity(UUID uuid) { final FaweCompoundTag entity = entity(uuid); if (entity == null) { @@ -63,7 +63,7 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent, ITileInput { @Nullable FaweCompoundTag entity(UUID uuid); @Override - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") default CompoundTag getTile(int x, int y, int z) { return IBlocks.super.getTile(x, y, z); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java index 13400f769..fc1482d6e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java @@ -38,7 +38,7 @@ public interface IChunkSet extends IBlocks, OutputExtent { boolean isEmpty(); @Override - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") default boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { return tile(x, y, z, FaweCompoundTag.of(tile.toLinTag())); } @@ -60,7 +60,7 @@ public interface IChunkSet extends IBlocks, OutputExtent { void setFullBright(int layer); - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") default void setEntity(CompoundTag tag) { entity(FaweCompoundTag.of(tag::toLinTag)); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/ITileInput.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/ITileInput.java index eb0503858..4a88118ef 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/ITileInput.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/ITileInput.java @@ -2,7 +2,7 @@ package com.fastasyncworldedit.core.queue; import com.sk89q.jnbt.CompoundTag; -@Deprecated(forRemoval = true, since = "TODO") +@Deprecated(forRemoval = true, since = "2.11.2") public interface ITileInput { CompoundTag getTile(int x, int y, int z); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java index 115397788..04da475e2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java @@ -428,7 +428,7 @@ public class MainUtil { * @deprecated use {@link NbtUtils#withPosition} instead */ @Nonnull - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") public static CompoundTag setPosition(@Nonnull CompoundTag tag, int x, int y, int z) { Map> value = new HashMap<>(tag.getValue()); value.put("x", new IntTag(x)); @@ -446,7 +446,7 @@ public class MainUtil { * @deprecated use {@link NbtUtils#withEntityInfo(LinCompoundTag, Entity)} instead */ @Nonnull - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") public static CompoundTag setEntityInfo(@Nonnull CompoundTag tag, @Nonnull Entity entity) { Map> map = new HashMap<>(tag.getValue()); map.put("Id", new StringTag(entity.getState().getType().id())); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java index 07a752131..ac606ab24 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java @@ -96,7 +96,7 @@ public final class NbtUtils { * * @param compoundTag the compound tag to extract uuid information from * @return the extracted UUID - * @since TODO + * @since 2.11.2 */ public static UUID uuid(FaweCompoundTag compoundTag) { final LinCompoundTag linTag = compoundTag.linTag(); @@ -139,7 +139,7 @@ public final class NbtUtils { * @param y New Y coordinate * @param z New Z coordinate * @return New tag - * @since TODO + * @since 2.11.2 */ public static @Nonnull LinCompoundTag withPosition(@Nonnull LinCompoundTag tag, int x, int y, int z) { return tag.toBuilder() @@ -157,7 +157,7 @@ public final class NbtUtils { * @param y New Y coordinate * @param z New Z coordinate * @return New tag - * @since TODO + * @since 2.11.2 */ public static @Nonnull FaweCompoundTag withPosition(@Nonnull FaweCompoundTag tag, int x, int y, int z) { return FaweCompoundTag.of(withPosition(tag.linTag(), x, y, z)); @@ -168,7 +168,7 @@ public final class NbtUtils { * * @param tag the tag to copy * @param entity the entity to use the Id and the Pos from - * @since TODO + * @since 2.11.2 */ public static @Nonnull LinCompoundTag withEntityInfo(@Nonnull LinCompoundTag tag, @Nonnull Entity entity) { final LinCompoundTag.Builder builder = tag.toBuilder() @@ -191,7 +191,7 @@ public final class NbtUtils { * * @param map the map to insert to * @param uuid the uuid to insert - * @since TODO + * @since 2.11.2 */ public static void addUUIDToMap(Map> map, UUID uuid) { int[] uuidArray = new int[4]; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/block/CompoundInput.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/block/CompoundInput.java index eff3c3de6..37c63a042 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/block/CompoundInput.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/block/CompoundInput.java @@ -21,7 +21,7 @@ public enum CompoundInput { } }; - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") public BaseBlock get(BlockState state, ITileInput input, int x, int y, int z) { return state.toBaseBlock(); } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java index 11143a6c7..9b28a6d30 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java @@ -174,7 +174,7 @@ public final class NBTUtils { * @since 2.4.0 * @deprecated use {@link com.fastasyncworldedit.core.util.NbtUtils#addUUIDToMap(Map, UUID)} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") public static void addUUIDToMap(Map> map, UUID uuid) { int[] uuidArray = new int[4]; uuidArray[0] = (int) (uuid.getMostSignificantBits() >> 32); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java index 1e988b51f..b38e2dc2d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java @@ -72,7 +72,7 @@ public interface OutputExtent { /** * @deprecated use {@link #tile(int, int, int, FaweCompoundTag)} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") default boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { return tile(x, y, z, FaweCompoundTag.of(tile.toLinTag())); } @@ -84,7 +84,7 @@ public interface OutputExtent { * @param z the z position * @param tile the tile/block entity to set * @return {@code true} if the tile/block entity was placed - * @since TODO + * @since 2.11.2 */ boolean tile(int x, int y, int z, FaweCompoundTag tile) throws WorldEditException; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index e67c28abf..9ff666f79 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -209,7 +209,7 @@ public class BlockArrayClipboard implements Clipboard { } - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") public boolean setTile(BlockVector3 position, CompoundTag tag) { return tile(position.x(), position.y(), position.z(), FaweCompoundTag.of(tag.toLinTag())); } 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 d8dc989da..017ec7ca0 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 @@ -852,7 +852,7 @@ public abstract class BlockVector3 { return orDefault.getBiome(this); } - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.2") public CompoundTag getNbtData(Extent orDefault) { return orDefault.getFullBlock(x(), y(), z()).getNbtData(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockMaterial.java index d37929a37..243acb171 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockMaterial.java @@ -196,7 +196,7 @@ public interface BlockMaterial { /** * {@return the default tile associated with this material, if any} - * @since TODO + * @since 2.11.2 */ @Nullable FaweCompoundTag defaultTile(); From 526f1f7b7632b149ae1daba5c1b4aa61bb03f856 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 15 Sep 2024 17:23:15 +0200 Subject: [PATCH 381/466] Back to snapshot for development Signed-off-by: Alexander Brandes --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index afe45594c..dddd41149 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s-%s", rootVersion, buildNumber) +version = String.format("%s", rootVersion) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From c2496543bd2e121fd4d253abd15122e026baf6f7 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 15 Sep 2024 17:32:58 +0200 Subject: [PATCH 382/466] Update runServer task for 1.21.1 Signed-off-by: Alexander Brandes --- build.gradle.kts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index dddd41149..adab2bddb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.11.2") +var rootVersion by extra("2.11.3") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s", rootVersion) +version = String.format("%s-%s", rootVersion, buildNumber) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") @@ -97,7 +97,7 @@ tasks { } } runServer { - minecraftVersion("1.20.4") + minecraftVersion("1.21.1") pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile } .toTypedArray()) From b5be1477a50da3e25ef21eeab5fa62206392f85b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 00:46:47 +0000 Subject: [PATCH 383/466] Update dependency com.gradleup.shadow:shadow-gradle-plugin to v8.3.1 (#2915) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 7b227e2d8..b4d03430f 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -23,7 +23,7 @@ val properties = Properties().also { props -> dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2") - implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.0") + implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.1") implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.2") constraints { val asmVersion = "[9.7,)" From 7010c8181ffaa7b446e92ac6f01183f0df1027c6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 00:47:02 +0000 Subject: [PATCH 384/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.4.1 (#2916) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 004644b3f..3927910c9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.3.13" +towny = "0.100.4.1" plotsquared = "7.3.10" # Third party From 789907e56b8911fb259e3afed4e68cd591a66ca0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 04:04:37 +0000 Subject: [PATCH 385/466] Update dependency gradle to v8.10.1 (#2918) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9355b4155..0aaefbcaf 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 71b99f9b05805832ef90bf70ac2d5bf5d30ca97c Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Mon, 16 Sep 2024 20:41:58 +0200 Subject: [PATCH 386/466] Revert history writing using LinBinaryIO (#2919) --- .../changeset/FaweStreamChangeSet.java | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java index 613b8def8..e50030d21 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java @@ -22,12 +22,9 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockTypes; -import org.enginehub.linbus.stream.LinBinaryIO; -import org.enginehub.linbus.tree.LinRootEntry; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.DataOutput; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; @@ -405,8 +402,8 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { public void addTileCreate(final FaweCompoundTag tag) { blockSize++; try { - DataOutput nbtos = getTileCreateOS(); - LinBinaryIO.write(nbtos, new LinRootEntry("tile-create", tag.linTag())); + NBTOutputStream nbtos = getTileCreateOS(); + nbtos.writeTag(new CompoundTag(tag.linTag())); } catch (IOException e) { e.printStackTrace(); } @@ -416,8 +413,8 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { public void addTileRemove(final FaweCompoundTag tag) { blockSize++; try { - DataOutput nbtos = getTileRemoveOS(); - LinBinaryIO.write(nbtos, new LinRootEntry("tile-remove", tag.linTag())); + NBTOutputStream nbtos = getTileRemoveOS(); + nbtos.writeTag(new CompoundTag(tag.linTag())); } catch (IOException e) { e.printStackTrace(); } @@ -427,8 +424,8 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { public void addEntityRemove(final FaweCompoundTag tag) { blockSize++; try { - DataOutput nbtos = getEntityRemoveOS(); - LinBinaryIO.write(nbtos, new LinRootEntry("entity-remove", tag.linTag())); + NBTOutputStream nbtos = getEntityRemoveOS(); + nbtos.writeTag(new CompoundTag(tag.linTag())); } catch (IOException e) { e.printStackTrace(); } @@ -438,8 +435,8 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { public void addEntityCreate(final FaweCompoundTag tag) { blockSize++; try { - DataOutput nbtos = getEntityCreateOS(); - LinBinaryIO.write(nbtos, new LinRootEntry("entity-create", tag.linTag())); + NBTOutputStream nbtos = getEntityCreateOS(); + nbtos.writeTag(new CompoundTag(tag.linTag())); } catch (IOException e) { e.printStackTrace(); } From d9d5b7b4884860857b141deb5a42b29f5e502b1c Mon Sep 17 00:00:00 2001 From: Jordan Date: Tue, 17 Sep 2024 16:52:46 +0100 Subject: [PATCH 387/466] feat: improve fawe limits (#2773) (#2858) * feat: improve fawe limits (#2773) - add FaweLimit implementations for increasing concurrency levels - allow FaweLimit to perform processing (and forcefully disable as required) to capture [tile] entities - Use `BlockVector3#set(Extent orDefault)` where appropriate to reduce block checks - fixes #2679 - fixes #1874 (cherry picked from commit 6052fc3128410ec5dc9c2703b497082b8647d22c) * fix: actually apply a filter if applied from a full region chunk section - cannot remember why I made this change in the first place in #2773 but this fixes edits having "empty middles" - doesn't seem to have broken anything in testing * Reduce limit to always atomic --- .../fastasyncworldedit/core/FaweCache.java | 11 +- .../core/configuration/Settings.java | 40 ++-- .../platform/binding/EditSessionHolder.java | 7 + .../platform/binding/ProvideBindings.java | 34 ++- .../core/extent/LimitExtent.java | 196 +++++++++--------- .../extent/filter/block/CharFilterBlock.java | 1 - .../core/function/mask/ABlockMask.java | 2 +- .../core/function/mask/DataMask.java | 4 +- .../core/function/mask/IdMask.java | 4 +- .../function/mask/SingleBlockStateMask.java | 2 +- .../core/function/mask/SplatterBrushMask.java | 2 +- .../core/limit/FaweLimit.java | 134 ++++++++---- .../core/queue/IBatchProcessor.java | 2 +- .../java/com/sk89q/worldedit/EditSession.java | 19 +- .../sk89q/worldedit/EditSessionBuilder.java | 6 +- .../com/sk89q/worldedit/LocalSession.java | 2 +- .../worldedit/command/BiomeCommands.java | 2 + .../worldedit/command/BrushCommands.java | 10 +- .../worldedit/command/ClipboardCommands.java | 11 +- .../worldedit/command/GenerationCommands.java | 19 +- .../worldedit/command/HistoryCommands.java | 3 + .../worldedit/command/RegionCommands.java | 20 +- .../command/SnapshotUtilCommands.java | 2 + .../worldedit/command/UtilityCommands.java | 62 ++---- .../command/tool/BlockDataCyler.java | 2 +- .../worldedit/command/tool/BlockReplacer.java | 2 +- .../worldedit/command/tool/SinglePickaxe.java | 2 +- .../worldedit/command/tool/StackTool.java | 2 +- .../worldedit/command/tool/TreePlanter.java | 2 +- .../worldedit/command/tool/brush/Brush.java | 11 + .../util/annotation/ConfirmHandler.java | 2 +- .../util/annotation/PreloadHandler.java | 2 +- .../SynchronousSettingExpected.java | 22 ++ .../command/util/annotation/package-info.java | 1 + .../platform/PlatformCommandManager.java | 23 +- .../worldedit/function/mask/BiomeMask.java | 2 +- .../function/mask/BlockCategoryMask.java | 2 +- .../worldedit/function/mask/BlockMask.java | 2 +- .../function/mask/BlockStateMask.java | 2 +- .../function/mask/BlockTypeMask.java | 2 +- .../function/mask/ExistingBlockMask.java | 2 +- .../mask/InverseSingleBlockStateMask.java | 2 +- .../src/main/resources/lang/strings.json | 2 + 43 files changed, 400 insertions(+), 282 deletions(-) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/EditSessionHolder.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/SynchronousSettingExpected.java diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java index 526570296..3ed494298 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java @@ -192,17 +192,22 @@ public enum FaweCache implements Trimable { Type.OUTSIDE_REGION ); public static final FaweException MAX_CHECKS = new FaweException( - Caption.of("fawe.cancel.reason.max" + ".checks"), + Caption.of("fawe.cancel.reason.max.checks"), + Type.MAX_CHECKS, + true + ); + public static final FaweException MAX_FAILS = new FaweException( + Caption.of("fawe.cancel.reason.max.fails"), Type.MAX_CHECKS, true ); public static final FaweException MAX_CHANGES = new FaweException( - Caption.of("fawe.cancel.reason.max" + ".changes"), + Caption.of("fawe.cancel.reason.max.changes"), Type.MAX_CHANGES, false ); public static final FaweException LOW_MEMORY = new FaweException( - Caption.of("fawe.cancel.reason.low" + ".memory"), + Caption.of("fawe.cancel.reason.low.memory"), Type.LOW_MEMORY, false ); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index d35219bec..60ec9311a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -123,29 +123,31 @@ public class Settings extends Config { limit.MAX_ACTIONS, newLimit.MAX_ACTIONS != -1 ? newLimit.MAX_ACTIONS : Integer.MAX_VALUE ); - limit.MAX_CHANGES = Math.max( - limit.MAX_CHANGES, + limit.MAX_CHANGES.set(Math.max( + limit.MAX_CHANGES.get(), newLimit.MAX_CHANGES != -1 ? newLimit.MAX_CHANGES : Long.MAX_VALUE - ); - limit.MAX_BLOCKSTATES = Math.max( - limit.MAX_BLOCKSTATES, + )); + limit.MAX_BLOCKSTATES.set(Math.max( + limit.MAX_BLOCKSTATES.get(), newLimit.MAX_BLOCKSTATES != -1 ? newLimit.MAX_BLOCKSTATES : Integer.MAX_VALUE - ); - limit.MAX_CHECKS = Math.max( - limit.MAX_CHECKS, + )); + limit.MAX_CHECKS.set(Math.max( + limit.MAX_CHECKS.get(), newLimit.MAX_CHECKS != -1 ? newLimit.MAX_CHECKS : Long.MAX_VALUE - ); - limit.MAX_ENTITIES = Math.max( - limit.MAX_ENTITIES, + )); + limit.MAX_ENTITIES.set(Math.max( + limit.MAX_ENTITIES.get(), newLimit.MAX_ENTITIES != -1 ? newLimit.MAX_ENTITIES : Integer.MAX_VALUE - ); - limit.MAX_FAILS = Math.max(limit.MAX_FAILS, newLimit.MAX_FAILS != -1 ? newLimit.MAX_FAILS : Integer.MAX_VALUE); - limit.MAX_ITERATIONS = Math.max( - limit.MAX_ITERATIONS, newLimit.MAX_ITERATIONS != -1 ? newLimit.MAX_ITERATIONS : Integer.MAX_VALUE); - limit.MAX_RADIUS = Math.max( - limit.MAX_RADIUS, - newLimit.MAX_RADIUS != -1 ? newLimit.MAX_RADIUS : Integer.MAX_VALUE - ); + )); + limit.MAX_FAILS.set(Math.max( + limit.MAX_FAILS.get(), + newLimit.MAX_FAILS != -1 ? newLimit.MAX_FAILS : Integer.MAX_VALUE + )); + limit.MAX_ITERATIONS.set(Math.max( + limit.MAX_ITERATIONS.get(), + newLimit.MAX_ITERATIONS != -1 ? newLimit.MAX_ITERATIONS : Integer.MAX_VALUE + )); + limit.MAX_RADIUS = Math.max(limit.MAX_RADIUS, newLimit.MAX_RADIUS != -1 ? newLimit.MAX_RADIUS : Integer.MAX_VALUE); limit.MAX_SUPER_PICKAXE_SIZE = Math.max( limit.MAX_SUPER_PICKAXE_SIZE, newLimit.MAX_SUPER_PICKAXE_SIZE != -1 ? newLimit.MAX_SUPER_PICKAXE_SIZE : Integer.MAX_VALUE diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/EditSessionHolder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/EditSessionHolder.java new file mode 100644 index 000000000..1fd588ec4 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/EditSessionHolder.java @@ -0,0 +1,7 @@ +package com.fastasyncworldedit.core.extension.platform.binding; + +import com.sk89q.worldedit.EditSession; + +public record EditSessionHolder(EditSession session) { + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java index bc1e2bfbf..9ac01d9c3 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java @@ -3,7 +3,11 @@ package com.fastasyncworldedit.core.extension.platform.binding; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.database.DBHandler; import com.fastasyncworldedit.core.database.RollbackDatabase; +import com.fastasyncworldedit.core.extent.LimitExtent; +import com.fastasyncworldedit.core.extent.processor.ExtentBatchProcessorHolder; +import com.fastasyncworldedit.core.internal.exception.FaweException; import com.fastasyncworldedit.core.regions.FaweMaskManager; +import com.fastasyncworldedit.core.util.ExtentTraverser; import com.fastasyncworldedit.core.util.TextureUtil; import com.fastasyncworldedit.core.util.image.ImageUtil; import com.sk89q.worldedit.EditSession; @@ -11,6 +15,7 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.command.util.annotation.AllowedRegion; +import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.platform.Actor; @@ -25,6 +30,7 @@ import org.enginehub.piston.inject.Key; import org.enginehub.piston.util.ValueProvider; import java.awt.image.BufferedImage; +import java.lang.reflect.Method; import java.net.URI; import java.util.Optional; @@ -52,11 +58,33 @@ public class ProvideBindings extends Bindings { @Binding public EditSession editSession(LocalSession localSession, Actor actor, InjectedValueAccess context) { + Method commandMethod = + context.injectedValue(Key.of(InjectedValueStore.class)).get().injectedValue(Key.of(Method.class)).get(); + Arguments arguments = context.injectedValue(Key.of(Arguments.class)).orElse(null); String command = arguments == null ? null : arguments.get(); - EditSession editSession = localSession.createEditSession(actor, command); - editSession.enableStandardMode(); - Request.request().setEditSession(editSession); + boolean synchronousSetting = commandMethod.getAnnotation(SynchronousSettingExpected.class) != null; + EditSessionHolder holder = context.injectedValue(Key.of(EditSessionHolder.class)).orElse(null); + EditSession editSession = holder != null ? holder.session() : null; + if (editSession == null) { + editSession = localSession.createEditSession(actor, command); + editSession.enableStandardMode(); + } else { + LimitExtent limitExtent = new ExtentTraverser<>(editSession).findAndGet(LimitExtent.class); + if (limitExtent != null) { + limitExtent.setProcessing(!synchronousSetting); + if (!synchronousSetting) { + ExtentBatchProcessorHolder processorHolder = new ExtentTraverser<>(editSession).findAndGet( + ExtentBatchProcessorHolder.class); + if (processorHolder != null) { + processorHolder.addProcessor(limitExtent); + } else { + throw new FaweException(Caption.of("fawe.error.no-process-non-synchronous-edit")); + } + } + } + Request.request().setEditSession(editSession); + } return editSession; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java index d02ff9320..d43078354 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java @@ -1,11 +1,15 @@ package com.fastasyncworldedit.core.extent; import com.fastasyncworldedit.core.extent.filter.block.ExtentFilterBlock; -import com.fastasyncworldedit.core.function.generator.GenBase; -import com.fastasyncworldedit.core.function.generator.Resource; +import com.fastasyncworldedit.core.extent.processor.ProcessorScope; import com.fastasyncworldedit.core.internal.exception.FaweException; import com.fastasyncworldedit.core.limit.FaweLimit; import com.fastasyncworldedit.core.queue.Filter; +import com.fastasyncworldedit.core.queue.IBatchProcessor; +import com.fastasyncworldedit.core.queue.IChunk; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import com.fastasyncworldedit.core.util.ExtentTraverser; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEditException; @@ -17,7 +21,6 @@ import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.formatting.text.Component; @@ -37,18 +40,22 @@ import java.util.Set; import java.util.UUID; import java.util.function.Consumer; -public class LimitExtent extends AbstractDelegateExtent { +public class LimitExtent extends AbstractDelegateExtent implements IBatchProcessor { private final FaweLimit limit; private final boolean[] faweExceptionReasonsUsed = new boolean[FaweException.Type.values().length]; private final Consumer onErrorMessage; + private final int chunk_size; + private boolean processing; /** * Create a new instance. * * @param extent the extent * @param limit the limit + * @deprecated Use {@link LimitExtent#LimitExtent(Extent, FaweLimit, Consumer, boolean)} */ + @Deprecated(forRemoval = true, since = "TODO") public LimitExtent(Extent extent, FaweLimit limit) { this(extent, limit, c -> { }); @@ -60,11 +67,33 @@ public class LimitExtent extends AbstractDelegateExtent { * @param extent the extent * @param limit the limit * @param onErrorMessage consumer to handle a component generated by exceptions + * @deprecated Use {@link LimitExtent#LimitExtent(Extent, FaweLimit, Consumer, boolean)} */ + @Deprecated(forRemoval = true, since = "TODO") public LimitExtent(Extent extent, FaweLimit limit, Consumer onErrorMessage) { + this(extent, limit, onErrorMessage, false); + } + + /** + * Create a new instance. + * + * @param extent the extent + * @param limit the limit + * @param onErrorMessage consumer to handle a component generated by exceptions + * @param processing if this limit extent is expected to be processing + * @since TODO + */ + public LimitExtent( + Extent extent, + FaweLimit limit, + Consumer onErrorMessage, + boolean processing + ) { super(extent); this.limit = limit; this.onErrorMessage = onErrorMessage; + this.chunk_size = 16 * 16 * (extent.getMaxY() - extent.getMinY()); + this.processing = processing; } private void handleException(FaweException e) { @@ -81,7 +110,7 @@ public class LimitExtent extends AbstractDelegateExtent { public List getEntities(Region region) { limit.THROW_MAX_CHECKS(region.getVolume()); try { - return super.getEntities(region); + return extent.getEntities(region); } catch (FaweException e) { handleException(e); return Collections.emptyList(); @@ -92,7 +121,7 @@ public class LimitExtent extends AbstractDelegateExtent { public List getEntities() { limit.THROW_MAX_CHECKS(); try { - return super.getEntities(); + return extent.getEntities(); } catch (FaweException e) { handleException(e); return Collections.emptyList(); @@ -105,7 +134,7 @@ public class LimitExtent extends AbstractDelegateExtent { limit.THROW_MAX_CHANGES(); limit.THROW_MAX_ENTITIES(); try { - return super.createEntity(location, entity); + return extent.createEntity(location, entity); } catch (FaweException e) { handleException(e); return null; @@ -118,7 +147,7 @@ public class LimitExtent extends AbstractDelegateExtent { limit.THROW_MAX_CHANGES(); limit.THROW_MAX_ENTITIES(); try { - return super.createEntity(location, entity, uuid); + return extent.createEntity(location, entity, uuid); } catch (FaweException e) { handleException(e); return null; @@ -130,7 +159,7 @@ public class LimitExtent extends AbstractDelegateExtent { limit.THROW_MAX_CHANGES(); limit.THROW_MAX_ENTITIES(); try { - super.removeEntity(x, y, z, uuid); + extent.removeEntity(x, y, z, uuid); } catch (FaweException e) { handleException(e); } @@ -138,9 +167,9 @@ public class LimitExtent extends AbstractDelegateExtent { @Override public boolean regenerateChunk(int x, int z, @Nullable BiomeType type, @Nullable Long seed) { - limit.THROW_MAX_CHANGES(Character.MAX_VALUE); + limit.THROW_MAX_CHANGES(chunk_size); try { - return super.regenerateChunk(x, z, type, seed); + return extent.regenerateChunk(x, z, type, seed); } catch (FaweException e) { handleException(e); return false; @@ -151,7 +180,7 @@ public class LimitExtent extends AbstractDelegateExtent { public int getHighestTerrainBlock(int x, int z, int minY, int maxY) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return super.getHighestTerrainBlock(x, z, minY, maxY); + return extent.getHighestTerrainBlock(x, z, minY, maxY); } catch (FaweException e) { handleException(e); return minY; @@ -162,7 +191,7 @@ public class LimitExtent extends AbstractDelegateExtent { public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return super.getHighestTerrainBlock(x, z, minY, maxY, filter); + return extent.getHighestTerrainBlock(x, z, minY, maxY, filter); } catch (FaweException e) { handleException(e); return minY; @@ -173,7 +202,7 @@ public class LimitExtent extends AbstractDelegateExtent { public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return super.getNearestSurfaceLayer(x, z, y, minY, maxY); + return extent.getNearestSurfaceLayer(x, z, y, minY, maxY); } catch (FaweException e) { handleException(e); return minY; @@ -184,7 +213,7 @@ public class LimitExtent extends AbstractDelegateExtent { public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir); + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir); } catch (FaweException e) { handleException(e); return minY; @@ -195,7 +224,7 @@ public class LimitExtent extends AbstractDelegateExtent { public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY); + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY); } catch (FaweException e) { handleException(e); return minY; @@ -206,7 +235,7 @@ public class LimitExtent extends AbstractDelegateExtent { public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax); + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax); } catch (FaweException e) { handleException(e); return minY; @@ -217,7 +246,7 @@ public class LimitExtent extends AbstractDelegateExtent { public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask); + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask); } catch (FaweException e) { handleException(e); return minY; @@ -237,91 +266,47 @@ public class LimitExtent extends AbstractDelegateExtent { ) { limit.THROW_MAX_CHECKS(maxY - minY + 1); try { - return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir); + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir); } catch (FaweException e) { handleException(e); return minY; } } - @Override - public void addCaves(Region region) throws WorldEditException { - limit.THROW_MAX_CHECKS(region.getVolume()); - limit.THROW_MAX_CHANGES(region.getVolume()); - super.addCaves(region); - } - - @Override - public void generate(Region region, GenBase gen) throws WorldEditException { - limit.THROW_MAX_CHECKS(region.getVolume()); - limit.THROW_MAX_CHANGES(region.getVolume()); - super.generate(region, gen); - } - - @Override - public void addSchems(Region region, Mask mask, List clipboards, int rarity, boolean rotate) throws - WorldEditException { - limit.THROW_MAX_CHECKS(region.getVolume()); - limit.THROW_MAX_CHANGES(region.getVolume()); - super.addSchems(region, mask, clipboards, rarity, rotate); - } - - @Override - public void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException { - limit.THROW_MAX_CHECKS(region.getVolume()); - limit.THROW_MAX_CHANGES(region.getVolume()); - super.spawnResource(region, gen, rarity, frequency); - } - - @Override - public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws - WorldEditException { - limit.THROW_MAX_CHECKS(region.getVolume()); - limit.THROW_MAX_CHANGES(region.getVolume()); - super.addOre(region, mask, material, size, frequency, rarity, minY, maxY); - } - - @Override - public void addOres(Region region, Mask mask) throws WorldEditException { - limit.THROW_MAX_CHECKS(region.getVolume()); - limit.THROW_MAX_CHANGES(region.getVolume()); - super.addOres(region, mask); - } - @Override public List> getBlockDistribution(Region region) { limit.THROW_MAX_CHECKS(region.getVolume()); - return super.getBlockDistribution(region); + return extent.getBlockDistribution(region); } @Override public List> getBlockDistributionWithData(Region region) { limit.THROW_MAX_CHECKS(region.getVolume()); - return super.getBlockDistributionWithData(region); + return extent.getBlockDistributionWithData(region); } @Override public int countBlocks(Region region, Set searchBlocks) { limit.THROW_MAX_CHECKS(region.getVolume()); - return super.countBlocks(region, searchBlocks); + return extent.countBlocks(region, searchBlocks); } @Override public int countBlocks(Region region, Mask searchMask) { limit.THROW_MAX_CHECKS(region.getVolume()); - return super.countBlocks(region, searchMask); + return extent.countBlocks(region, searchMask); } @Override public > int setBlocks(Region region, B block) throws MaxChangedBlocksException { limit.THROW_MAX_CHANGES(region.getVolume()); - return super.setBlocks(region, block); + return extent.setBlocks(region, block); } @Override public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException { limit.THROW_MAX_CHANGES(region.getVolume()); - return super.setBlocks(region, pattern); + return extent.setBlocks(region, pattern); } @Override @@ -329,41 +314,34 @@ public class LimitExtent extends AbstractDelegateExtent { MaxChangedBlocksException { limit.THROW_MAX_CHECKS(region.getVolume()); limit.THROW_MAX_CHANGES(region.getVolume()); - return super.replaceBlocks(region, filter, replacement); + return extent.replaceBlocks(region, filter, replacement); } @Override public int replaceBlocks(Region region, Set filter, Pattern pattern) throws MaxChangedBlocksException { limit.THROW_MAX_CHECKS(region.getVolume()); limit.THROW_MAX_CHANGES(region.getVolume()); - return super.replaceBlocks(region, filter, pattern); + return extent.replaceBlocks(region, filter, pattern); } @Override public int replaceBlocks(Region region, Mask mask, Pattern pattern) throws MaxChangedBlocksException { limit.THROW_MAX_CHECKS(region.getVolume()); limit.THROW_MAX_CHANGES(region.getVolume()); - return super.replaceBlocks(region, mask, pattern); - } - - @Override - public int center(Region region, Pattern pattern) throws MaxChangedBlocksException { - limit.THROW_MAX_CHECKS(region.getVolume()); - limit.THROW_MAX_CHANGES(region.getVolume()); - return super.center(region, pattern); + return extent.replaceBlocks(region, mask, pattern); } @Override public int setBlocks(Set vset, Pattern pattern) { limit.THROW_MAX_CHANGES(vset.size()); - return super.setBlocks(vset, pattern); + return extent.setBlocks(vset, pattern); } @Override public T apply(Region region, T filter, boolean full) { limit.THROW_MAX_CHECKS(region.getVolume()); limit.THROW_MAX_CHANGES(region.getVolume()); - return super.apply(region, filter, full); + return extent.apply(region, filter, full); } @Override @@ -393,14 +371,14 @@ public class LimitExtent extends AbstractDelegateExtent { } limit.THROW_MAX_CHECKS(size); limit.THROW_MAX_CHANGES(size); - return super.apply(positions, filter); + return extent.apply(positions, filter); } @Override public BlockState getBlock(BlockVector3 position) { limit.THROW_MAX_CHECKS(); try { - return super.getBlock(position); + return extent.getBlock(position); } catch (FaweException e) { handleException(e); return BlockTypes.AIR.getDefaultState(); @@ -411,7 +389,7 @@ public class LimitExtent extends AbstractDelegateExtent { public BlockState getBlock(int x, int y, int z) { limit.THROW_MAX_CHECKS(); try { - return super.getBlock(x, y, z); + return extent.getBlock(x, y, z); } catch (FaweException e) { handleException(e); return BlockTypes.AIR.getDefaultState(); @@ -422,7 +400,7 @@ public class LimitExtent extends AbstractDelegateExtent { public BaseBlock getFullBlock(BlockVector3 position) { limit.THROW_MAX_CHECKS(); try { - return super.getFullBlock(position); + return extent.getFullBlock(position); } catch (FaweException e) { handleException(e); return BlockTypes.AIR.getDefaultState().toBaseBlock(); @@ -433,7 +411,7 @@ public class LimitExtent extends AbstractDelegateExtent { public BaseBlock getFullBlock(int x, int y, int z) { limit.THROW_MAX_CHECKS(); try { - return super.getFullBlock(x, y, z); + return extent.getFullBlock(x, y, z); } catch (FaweException e) { handleException(e); return BlockTypes.AIR.getDefaultState().toBaseBlock(); @@ -444,7 +422,7 @@ public class LimitExtent extends AbstractDelegateExtent { public BiomeType getBiome(BlockVector3 position) { limit.THROW_MAX_CHECKS(); try { - return super.getBiome(position); + return extent.getBiome(position); } catch (FaweException e) { handleException(e); return BiomeTypes.FOREST; @@ -455,7 +433,7 @@ public class LimitExtent extends AbstractDelegateExtent { public BiomeType getBiomeType(int x, int y, int z) { limit.THROW_MAX_CHECKS(); try { - return super.getBiomeType(x, y, z); + return extent.getBiomeType(x, y, z); } catch (FaweException e) { handleException(e); return BiomeTypes.FOREST; @@ -470,7 +448,7 @@ public class LimitExtent extends AbstractDelegateExtent { limit.THROW_MAX_BLOCKSTATES(); } try { - return super.setBlock(position, block); + return extent.setBlock(position, block); } catch (FaweException e) { handleException(e); return false; @@ -484,7 +462,7 @@ public class LimitExtent extends AbstractDelegateExtent { limit.THROW_MAX_BLOCKSTATES(); } try { - return super.setBlock(x, y, z, block); + return extent.setBlock(x, y, z, block); } catch (FaweException e) { handleException(e); return false; @@ -494,9 +472,9 @@ public class LimitExtent extends AbstractDelegateExtent { @Override public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { limit.THROW_MAX_CHANGES(); - limit.MAX_BLOCKSTATES(); + limit.THROW_MAX_BLOCKSTATES(); try { - return super.setTile(x, y, z, tile); + return extent.setTile(x, y, z, tile); } catch (FaweException e) { handleException(e); return false; @@ -507,7 +485,7 @@ public class LimitExtent extends AbstractDelegateExtent { public boolean setBiome(BlockVector3 position, BiomeType biome) { limit.THROW_MAX_CHANGES(); try { - return super.setBiome(position, biome); + return extent.setBiome(position, biome); } catch (FaweException e) { handleException(e); return false; @@ -518,11 +496,41 @@ public class LimitExtent extends AbstractDelegateExtent { public boolean setBiome(int x, int y, int z, BiomeType biome) { limit.THROW_MAX_CHANGES(); try { - return super.setBiome(x, y, z, biome); + return extent.setBiome(x, y, z, biome); } catch (FaweException e) { handleException(e); return false; } } + public void setProcessing(boolean processing) { + this.processing = processing; + } + + @Override + public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { + if (!processing) { + return set; + } + int tiles = set.getTiles().size(); + int ents = set.getEntities().size() + set.getEntityRemoves().size(); + limit.THROW_MAX_CHANGES(tiles + ents); + limit.THROW_MAX_BLOCKSTATES(tiles); + limit.THROW_MAX_ENTITIES(ents); + return set; + } + + @Override + public Extent construct(final Extent child) { + if (extent != child) { + new ExtentTraverser(this).setNext(child); + } + return this; + } + + @Override + public ProcessorScope getScope() { + return ProcessorScope.READING_SET_BLOCKS; + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java index cafd4513a..718171efd 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java @@ -9,7 +9,6 @@ import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.implementation.Flood; import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; -import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ABlockMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ABlockMask.java index 7fdebdded..ed5b028dd 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ABlockMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/ABlockMask.java @@ -26,7 +26,7 @@ public abstract class ABlockMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - return test(getExtent().getBlock(vector)); + return test(vector.getBlock(getExtent())); } public abstract boolean test(BlockState state); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/DataMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/DataMask.java index 2b3ad7edb..84b8f77ad 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/DataMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/DataMask.java @@ -16,9 +16,9 @@ public class DataMask extends AbstractExtentMask implements ResettableMask { @Override public boolean test(BlockVector3 vector) { if (data != -1) { - return getExtent().getBlock(vector).getInternalPropertiesId() == data; + return vector.getBlock(getExtent()).getInternalPropertiesId() == data; } else { - data = getExtent().getBlock(vector).getInternalPropertiesId(); + data = vector.getBlock(getExtent()).getInternalPropertiesId(); return true; } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/IdMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/IdMask.java index 49c90183a..b0ba4fb59 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/IdMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/IdMask.java @@ -24,7 +24,9 @@ public class IdMask extends AbstractExtentMask implements ResettableMask { @Override public boolean test(BlockVector3 vector) { - return test(getExtent(), vector); + int blockID = vector.getBlock(getExtent()).getInternalBlockTypeId(); + int testId = id.compareAndExchange(-1, blockID); + return blockID == testId || testId == -1; } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SingleBlockStateMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SingleBlockStateMask.java index 32d853bda..400f32163 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SingleBlockStateMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SingleBlockStateMask.java @@ -30,7 +30,7 @@ public class SingleBlockStateMask extends ABlockMask { @Override public boolean test(BlockVector3 vector) { - int test = getExtent().getBlock(vector).getOrdinal(); + int test = vector.getBlock(getExtent()).getOrdinal(); return ordinal == test || isAir && test == 0; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SplatterBrushMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SplatterBrushMask.java index 250969616..d80399be4 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SplatterBrushMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/SplatterBrushMask.java @@ -40,7 +40,7 @@ public class SplatterBrushMask extends AbstractExtentMask { double dist = vector.distanceSq(position); synchronized (placed) { if (dist < size2 && !placed.contains(vector) && ThreadLocalRandom.current().nextInt(5) < 2 && surface.test(vector)) { - placed.add(vector); + placed.add(vector.toImmutable()); return true; } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java index d17787f03..2bb002914 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java @@ -5,16 +5,18 @@ import com.fastasyncworldedit.core.configuration.Settings; import java.util.Collections; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; public class FaweLimit { public int MAX_ACTIONS = 0; - public long MAX_CHANGES = 0; - public int MAX_FAILS = 0; - public long MAX_CHECKS = 0; - public int MAX_ITERATIONS = 0; - public int MAX_BLOCKSTATES = 0; - public int MAX_ENTITIES = 0; + public AtomicLong MAX_CHANGES = new AtomicLong(); + public AtomicInteger MAX_FAILS = new AtomicInteger(); + public AtomicLong MAX_CHECKS = new AtomicLong(); + public AtomicInteger MAX_ITERATIONS = new AtomicInteger(); + public AtomicInteger MAX_BLOCKSTATES = new AtomicInteger(); + public AtomicInteger MAX_ENTITIES = new AtomicInteger(); public int MAX_HISTORY = 0; public int SCHEM_FILE_SIZE_LIMIT = 0; public int SCHEM_FILE_NUM_LIMIT = 0; @@ -112,12 +114,12 @@ public class FaweLimit { MAX.SPEED_REDUCTION = 0; MAX.INVENTORY_MODE = 0; MAX.MAX_ACTIONS = 1; - MAX.MAX_CHANGES = Long.MAX_VALUE; - MAX.MAX_FAILS = Integer.MAX_VALUE; - MAX.MAX_CHECKS = Long.MAX_VALUE; - MAX.MAX_ITERATIONS = Integer.MAX_VALUE; - MAX.MAX_BLOCKSTATES = Integer.MAX_VALUE; - MAX.MAX_ENTITIES = Integer.MAX_VALUE; + MAX.MAX_CHANGES = new AtomicLong(Long.MAX_VALUE); + MAX.MAX_FAILS = new AtomicInteger(Integer.MAX_VALUE); + MAX.MAX_CHECKS = new AtomicLong(Long.MAX_VALUE); + MAX.MAX_ITERATIONS = new AtomicInteger(Integer.MAX_VALUE); + MAX.MAX_BLOCKSTATES = new AtomicInteger(Integer.MAX_VALUE); + MAX.MAX_ENTITIES = new AtomicInteger(Integer.MAX_VALUE); MAX.MAX_HISTORY = Integer.MAX_VALUE; MAX.SCHEM_FILE_NUM_LIMIT = Integer.MAX_VALUE; MAX.SCHEM_FILE_SIZE_LIMIT = Integer.MAX_VALUE; @@ -138,120 +140,144 @@ public class FaweLimit { } public boolean MAX_CHANGES() { - return MAX_CHANGES-- > 0; + return MAX_CHANGES.decrementAndGet() < 0; } public boolean MAX_FAILS() { - return MAX_FAILS-- > 0; + return MAX_FAILS.decrementAndGet() < 0; } public boolean MAX_CHECKS() { - return MAX_CHECKS-- > 0; + return MAX_CHECKS.decrementAndGet() < 0; } public boolean MAX_ITERATIONS() { - return MAX_ITERATIONS-- > 0; + return MAX_ITERATIONS.decrementAndGet() < 0; } public boolean MAX_BLOCKSTATES() { - return MAX_BLOCKSTATES-- > 0; + return MAX_BLOCKSTATES.decrementAndGet() < 0; } public boolean MAX_ENTITIES() { - return MAX_ENTITIES-- > 0; + return MAX_ENTITIES.decrementAndGet() < 0; } public void THROW_MAX_CHANGES() { - if (MAX_CHANGES-- <= 0) { + if (MAX_CHANGES.decrementAndGet() < 0) { throw FaweCache.MAX_CHANGES; } } public void THROW_MAX_FAILS() { - if (MAX_FAILS-- <= 0) { - throw FaweCache.MAX_CHECKS; + if (MAX_FAILS.decrementAndGet() < 0) { + throw FaweCache.MAX_FAILS; } } public void THROW_MAX_CHECKS() { - if (MAX_CHECKS-- <= 0) { + if (MAX_CHECKS.decrementAndGet() < 0) { throw FaweCache.MAX_CHECKS; } } public void THROW_MAX_ITERATIONS() { - if (MAX_ITERATIONS-- <= 0) { + if (MAX_ITERATIONS.decrementAndGet() < 0) { throw FaweCache.MAX_ITERATIONS; } } public void THROW_MAX_BLOCKSTATES() { - if (MAX_BLOCKSTATES-- <= 0) { + if (MAX_BLOCKSTATES.decrementAndGet() < 0) { throw FaweCache.MAX_TILES; } } public void THROW_MAX_ENTITIES() { - if (MAX_ENTITIES-- <= 0) { + if (MAX_ENTITIES.decrementAndGet() < 0) { throw FaweCache.MAX_ENTITIES; } } public void THROW_MAX_CHANGES(int amt) { - if ((MAX_CHANGES -= amt) <= 0) { + if (amt == 0) { + return; + } + if (MAX_CHANGES.addAndGet(-amt) < 0) { throw FaweCache.MAX_CHANGES; } } public void THROW_MAX_CHANGES(long amt) { - if ((MAX_CHANGES -= amt) <= 0) { + if (amt == 0) { + return; + } + if (MAX_CHANGES.addAndGet(-amt) < 0) { throw FaweCache.MAX_CHANGES; } } public void THROW_MAX_FAILS(int amt) { - if ((MAX_FAILS -= amt) <= 0) { - throw FaweCache.MAX_CHECKS; + if (amt == 0) { + return; + } + if (MAX_FAILS.addAndGet(-amt) < 0) { + throw FaweCache.MAX_FAILS; } } public void THROW_MAX_CHECKS(int amt) { - if ((MAX_CHECKS -= amt) <= 0) { + if (amt == 0) { + return; + } + if (MAX_CHECKS.addAndGet(-amt) < 0) { throw FaweCache.MAX_CHECKS; } } public void THROW_MAX_CHECKS(long amt) { - if ((MAX_CHECKS -= amt) <= 0) { + if (amt == 0) { + return; + } + if (MAX_CHECKS.addAndGet(-amt) < 0) { throw FaweCache.MAX_CHECKS; } } public void THROW_MAX_ITERATIONS(int amt) { - if ((MAX_ITERATIONS -= amt) <= 0) { + if (amt == 0) { + return; + } + if (MAX_ITERATIONS.addAndGet(-amt) < 0) { throw FaweCache.MAX_ITERATIONS; } } public void THROW_MAX_BLOCKSTATES(int amt) { - if ((MAX_BLOCKSTATES -= amt) <= 0) { + if (amt == 0) { + return; + } + if (MAX_BLOCKSTATES.addAndGet(-amt) < 0) { throw FaweCache.MAX_TILES; } } public void THROW_MAX_ENTITIES(int amt) { - if ((MAX_ENTITIES -= amt) <= 0) { + if (amt == 0) { + return; + } + if (MAX_ENTITIES.addAndGet(-amt) < 0) { throw FaweCache.MAX_ENTITIES; } } public boolean isUnlimited() { - return MAX_CHANGES == Long.MAX_VALUE - && MAX_FAILS == Integer.MAX_VALUE - && MAX_CHECKS == Long.MAX_VALUE - && MAX_ITERATIONS == Integer.MAX_VALUE - && MAX_BLOCKSTATES == Integer.MAX_VALUE - && MAX_ENTITIES == Integer.MAX_VALUE + return MAX_CHANGES.get() == Long.MAX_VALUE + && MAX_FAILS.get() == Integer.MAX_VALUE + && MAX_CHECKS.get() == Long.MAX_VALUE + && MAX_ITERATIONS.get() == Integer.MAX_VALUE + && MAX_BLOCKSTATES.get() == Integer.MAX_VALUE + && MAX_ENTITIES.get() == Integer.MAX_VALUE && MAX_HISTORY == Integer.MAX_VALUE && SCHEM_FILE_SIZE_LIMIT == Integer.MAX_VALUE && SCHEM_FILE_NUM_LIMIT == Integer.MAX_VALUE @@ -270,14 +296,30 @@ public class FaweLimit { && MAX_BUTCHER_RADIUS == Integer.MAX_VALUE; } + /** + * Get an {@link FaweLimit} representing the amount of a limit used from a given "original" limit + * + * @since TODO + */ + public FaweLimit getLimitUsed(FaweLimit originalLimit) { + FaweLimit newLimit = new FaweLimit(); + newLimit.MAX_CHANGES = new AtomicLong(originalLimit.MAX_CHANGES.get() - this.MAX_CHANGES.get()); + newLimit.MAX_FAILS = new AtomicInteger(originalLimit.MAX_FAILS.get() - this.MAX_FAILS.get()); + newLimit.MAX_CHECKS = new AtomicLong(originalLimit.MAX_CHECKS.get() - this.MAX_CHECKS.get()); + newLimit.MAX_ITERATIONS = new AtomicInteger(originalLimit.MAX_ITERATIONS.get() - this.MAX_ITERATIONS.get()); + newLimit.MAX_BLOCKSTATES = new AtomicInteger(originalLimit.MAX_BLOCKSTATES.get() - this.MAX_BLOCKSTATES.get()); + newLimit.MAX_ENTITIES = new AtomicInteger(originalLimit.MAX_ENTITIES.get() - this.MAX_ENTITIES.get()); + return newLimit; + } + public void set(FaweLimit limit) { MAX_ACTIONS = limit.MAX_ACTIONS; - MAX_CHANGES = limit.MAX_CHANGES; - MAX_BLOCKSTATES = limit.MAX_BLOCKSTATES; - MAX_CHECKS = limit.MAX_CHECKS; - MAX_ENTITIES = limit.MAX_ENTITIES; - MAX_FAILS = limit.MAX_FAILS; - MAX_ITERATIONS = limit.MAX_ITERATIONS; + MAX_CHANGES.set(limit.MAX_CHANGES.get()); + MAX_FAILS.set(limit.MAX_FAILS.get()); + MAX_CHECKS.set(limit.MAX_CHECKS.get()); + MAX_ITERATIONS.set(limit.MAX_ITERATIONS.get()); + MAX_BLOCKSTATES.set(limit.MAX_BLOCKSTATES.get()); + MAX_ENTITIES.set(limit.MAX_ENTITIES.get()); MAX_HISTORY = limit.MAX_HISTORY; SCHEM_FILE_NUM_LIMIT = limit.SCHEM_FILE_NUM_LIMIT; SCHEM_FILE_SIZE_LIMIT = limit.SCHEM_FILE_SIZE_LIMIT; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java index 6b81b61f7..faec2f9f5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java @@ -50,7 +50,7 @@ public interface IBatchProcessor { } /** - * Convert this processor into an Extent based processor instead of a queue batch based on. + * Convert this processor into an Extent based processor instead of a queue batch based one. */ @Nullable Extent construct(Extent child); 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 4f987bd7e..85fbde830 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -308,16 +308,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { * @return Limit remaining */ public FaweLimit getLimitUsed() { - FaweLimit newLimit = new FaweLimit(); - newLimit.MAX_ACTIONS = originalLimit.MAX_ACTIONS - limit.MAX_ACTIONS; - newLimit.MAX_CHANGES = originalLimit.MAX_CHANGES - limit.MAX_CHANGES; - newLimit.MAX_FAILS = originalLimit.MAX_FAILS - limit.MAX_FAILS; - newLimit.MAX_CHECKS = originalLimit.MAX_CHECKS - limit.MAX_CHECKS; - newLimit.MAX_ITERATIONS = originalLimit.MAX_ITERATIONS - limit.MAX_ITERATIONS; - newLimit.MAX_BLOCKSTATES = originalLimit.MAX_BLOCKSTATES - limit.MAX_BLOCKSTATES; - newLimit.MAX_ENTITIES = originalLimit.MAX_ENTITIES - limit.MAX_ENTITIES; - newLimit.MAX_HISTORY = limit.MAX_HISTORY; - return newLimit; + return originalLimit.getLimitUsed(limit); } /** @@ -472,7 +463,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { */ @Deprecated public long getBlockChangeLimit() { - return originalLimit.MAX_CHANGES; + return originalLimit.MAX_CHANGES.get(); } /** @@ -481,7 +472,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { * @param limit the limit (>= 0) or -1 for no limit */ public void setBlockChangeLimit(long limit) { - this.limit.MAX_CHANGES = limit; + this.limit.MAX_CHANGES.set(limit); } /** @@ -1293,8 +1284,8 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { Operations.completeBlindly(commit()); // Check fails FaweLimit used = getLimitUsed(); - if (used.MAX_FAILS > 0) { - if (used.MAX_CHANGES > 0 || used.MAX_ENTITIES > 0) { + if (used.MAX_FAILS.get() > 0) { + if (used.MAX_CHANGES.get() > 0 || used.MAX_ENTITIES.get() > 0) { actor.print(Caption.of("fawe.error.worldedit.some.fails", used.MAX_FAILS)); } else if (new ExtentTraverser<>(getExtent()).findAndGet(FaweRegionExtent.class) != null) { actor.print(Caption.of("fawe.cancel.reason.outside.region")); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java index ca6f3b6a5..26650bf9c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java @@ -635,7 +635,11 @@ public final class EditSessionBuilder { }; } if (limit != null && !limit.isUnlimited()) { - this.extent = new LimitExtent(this.extent, limit, onErrorMessage); + this.extent = new LimitExtent(this.extent, limit, onErrorMessage, placeChunks && combineStages); + // Only process if we're not necessarily going to catch tiles via Extent#setBlock, e.g. because using PQE methods + if (placeChunks && combineStages) { + queue.addProcessor((LimitExtent) this.extent); + } } this.extent = wrapExtent(this.extent, eventBus, event, EditSession.Stage.BEFORE_HISTORY); } 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 d82bcd463..51a03119f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -1725,6 +1725,7 @@ public class LocalSession implements TextureHolder { * @return an edit session */ public EditSession createEditSession(Actor actor) { + //FAWE start return createEditSession(actor, null); } @@ -1739,7 +1740,6 @@ public class LocalSession implements TextureHolder { } // Create an edit session - //FAWE start - we don't use the edit session builder yet EditSession editSession; EditSessionBuilder builder = WorldEdit.getInstance().newEditSessionBuilder().world(world); if (actor.isPlayer() && actor instanceof Player) { 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 a60968da1..1f551aefa 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 @@ -30,6 +30,7 @@ import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.command.util.annotation.Confirm; import com.sk89q.worldedit.command.util.annotation.Preload; +import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; @@ -179,6 +180,7 @@ public class BiomeCommands { ) @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected // TODO improve using filter/chunk-based-placement @Confirm(Confirm.Processor.REGION) @CommandPermissions("worldedit.biome.set") public void setBiome( 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 664e656c4..e6a211a4b 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 @@ -992,15 +992,15 @@ public class BrushCommands { Expression radius, @Arg(desc = "Command to run") List input, - @Switch(name = 'p', desc = "Show any printed output") - boolean print + @Switch(name = 'h', desc = "Hide any printed output") + boolean hide ) throws WorldEditException { worldEdit.checkMaxBrushRadius( radius, context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player")) ); String cmd = StringMan.join(input, " "); - set(context, new CommandBrush(cmd, print), "worldedit.brush.command").setSize(radius); + set(context, new CommandBrush(cmd, !hide), "worldedit.brush.command").setSize(radius); } @Command( @@ -1414,7 +1414,7 @@ public class BrushCommands { //FAWE start FaweLimit limit = Settings.settings().getLimit(player); - iterations = Math.min(limit.MAX_ITERATIONS, iterations); + iterations = Math.min(limit.MAX_ITERATIONS.get(), iterations); //FAWE end set(context, new SmoothBrush(iterations, mask), "worldedit.brush.smooth").setSize(radius); @@ -1452,7 +1452,7 @@ public class BrushCommands { //FAWE start FaweLimit limit = Settings.settings().getLimit(player); - iterations = Math.min(limit.MAX_ITERATIONS, iterations); + iterations = Math.min(limit.MAX_ITERATIONS.get(), iterations); //FAWE end set(context, new SnowSmoothBrush(iterations, snowBlockCount, mask), "worldedit.brush.snowsmooth").setSize(radius); 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 378449755..bb42e7095 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 @@ -47,6 +47,7 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.annotation.Confirm; import com.sk89q.worldedit.command.util.annotation.Preload; +import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; @@ -153,7 +154,7 @@ public class ClipboardCommands { ((long) max.x() - (long) min.x() + 1) * ((long) max.y() - (long) min.y() + 1) * ((long) max.z() - (long) min .z() + 1); FaweLimit limit = actor.getLimit(); - if (volume >= limit.MAX_CHECKS) { + if (volume >= limit.MAX_CHECKS.get()) { throw FaweCache.MAX_CHECKS; } session.setClipboard(null); @@ -187,7 +188,7 @@ public class ClipboardCommands { long volume = (((long) max.x() - (long) min.x() + 1) * ((long) max.y() - (long) min.y() + 1) * ((long) max.z() - (long) min .z() + 1)); FaweLimit limit = actor.getLimit(); - if (volume >= limit.MAX_CHECKS) { + if (volume >= limit.MAX_CHECKS.get()) { throw FaweCache.MAX_CHECKS; } session.setClipboard(null); @@ -260,10 +261,10 @@ public class ClipboardCommands { long volume = (((long) max.x() - (long) min.x() + 1) * ((long) max.y() - (long) min.y() + 1) * ((long) max.z() - (long) min .z() + 1)); FaweLimit limit = actor.getLimit(); - if (volume >= limit.MAX_CHECKS) { + if (volume >= limit.MAX_CHECKS.get()) { throw FaweCache.MAX_CHECKS; } - if (volume >= limit.MAX_CHANGES) { + if (volume >= limit.MAX_CHANGES.get()) { throw FaweCache.MAX_CHANGES; } session.setClipboard(null); @@ -438,6 +439,7 @@ public class ClipboardCommands { desc = "Place the clipboard's contents without applying transformations (e.g. rotate)" ) @CommandPermissions("worldedit.clipboard.place") + @SynchronousSettingExpected @Logging(PLACEMENT) public void place( Actor actor, World world, LocalSession session, final EditSession editSession, @@ -502,6 +504,7 @@ public class ClipboardCommands { desc = "Paste the clipboard's contents" ) @CommandPermissions("worldedit.clipboard.paste") + @SynchronousSettingExpected @Logging(PLACEMENT) public void paste( Actor actor, World world, LocalSession session, EditSession editSession, 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 4b2f98e0c..f2a3c80ed 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 @@ -38,6 +38,7 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.annotation.Confirm; import com.sk89q.worldedit.command.util.annotation.Preload; +import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.mask.Mask; @@ -104,6 +105,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.cylinder") @Logging(PLACEMENT) + @SynchronousSettingExpected public int hcyl( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") @@ -152,6 +154,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.cylinder") @Logging(PLACEMENT) + @SynchronousSettingExpected public int cyl( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") @@ -197,6 +200,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.cone") @Logging(PLACEMENT) + @SynchronousSettingExpected public int cone(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") Pattern pattern, @@ -243,6 +247,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.sphere") @Logging(PLACEMENT) + @SynchronousSettingExpected public int hsphere( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") @@ -262,6 +267,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.sphere") @Logging(PLACEMENT) + @SynchronousSettingExpected public int sphere( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") @@ -313,6 +319,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.forest") @Logging(POSITION) + @SynchronousSettingExpected public int forestGen( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The size of the forest, in blocks", def = "10") @@ -337,6 +344,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.pumpkins") @Logging(POSITION) + @SynchronousSettingExpected public int pumpkins( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The size of the patch", def = "10") @@ -357,6 +365,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.pyramid") @Logging(PLACEMENT) + @SynchronousSettingExpected public int hollowPyramid( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to set") @@ -373,6 +382,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.pyramid") @Logging(PLACEMENT) + @SynchronousSettingExpected public int pyramid( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to set") @@ -400,6 +410,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.shape") @Logging(ALL) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int generate( Actor actor, LocalSession session, EditSession editSession, @@ -486,6 +497,7 @@ public class GenerationCommands { @CommandPermissions("worldedit.generation.shape.biome") @Logging(ALL) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int generateBiome( Actor actor, LocalSession session, EditSession editSession, @@ -564,6 +576,7 @@ public class GenerationCommands { @CommandPermissions("worldedit.generation.caves") @Logging(PLACEMENT) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public void caves( Actor actor, LocalSession session, EditSession editSession, @Selection Region region, @@ -602,6 +615,7 @@ public class GenerationCommands { @CommandPermissions("worldedit.generation.ore") @Logging(PLACEMENT) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public void ores( Actor actor, @@ -621,6 +635,7 @@ public class GenerationCommands { desc = "Generate an image" ) @CommandPermissions("worldedit.generation.image") + @SynchronousSettingExpected @Logging(PLACEMENT) public void image( Actor actor, @@ -685,6 +700,7 @@ public class GenerationCommands { @CommandPermissions("worldedit.generation.ore") @Logging(PLACEMENT) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public void ore( Actor actor, @@ -719,8 +735,9 @@ public class GenerationCommands { desc = "Creates a distorted sphere" ) @Logging(PLACEMENT) + @SynchronousSettingExpected @CommandPermissions("worldedit.generation.blob") - public int blobBrush( + public int blob( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "Pattern") Pattern pattern, 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 d1a647587..ba736e45e 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 @@ -27,6 +27,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.annotation.Confirm; +import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.inventory.BlockBag; @@ -61,6 +62,7 @@ public class HistoryCommands { desc = "Undoes the last action (from history)" ) @CommandPermissions({"worldedit.history.undo", "worldedit.history.undo.self"}) + @SynchronousSettingExpected public void undo( Actor actor, LocalSession session, @Confirm(Confirm.Processor.LIMIT) @Arg(desc = "Number of undoes to perform", def = "1") @@ -108,6 +110,7 @@ public class HistoryCommands { desc = "Redoes the last action (from history)" ) @CommandPermissions({"worldedit.history.redo", "worldedit.history.redo.self"}) + @SynchronousSettingExpected public void redo( Actor actor, LocalSession session, @Confirm(Confirm.Processor.LIMIT) @Arg(desc = "Number of redoes to perform", def = "1") 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 6a121aa02..565aecb9a 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 @@ -35,6 +35,7 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.annotation.Confirm; import com.sk89q.worldedit.command.util.annotation.Preload; +import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.GroundFunction; @@ -225,6 +226,7 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.line") @Logging(REGION) + @SynchronousSettingExpected public int line( Actor actor, EditSession editSession, @Selection Region region, @@ -257,6 +259,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.curve") @Logging(REGION) @Confirm(Confirm.Processor.REGION) + @SynchronousSettingExpected public int curve( Actor actor, EditSession editSession, @Selection Region region, @@ -315,6 +318,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.overlay") @Logging(REGION) @Confirm(Confirm.Processor.REGION) + @SynchronousSettingExpected // TODO improve using filter/chunk-based-placement public int overlay( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to overlay") @@ -333,6 +337,7 @@ public class RegionCommands { @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) @Confirm(Confirm.Processor.REGION) + @SynchronousSettingExpected // TODO improve using filter/chunk-based-placement public void lay( Actor actor, EditSession editSession, @@ -369,6 +374,7 @@ public class RegionCommands { ) @Logging(REGION) @CommandPermissions("worldedit.region.center") + @SynchronousSettingExpected public int center( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to set") @@ -386,6 +392,8 @@ public class RegionCommands { @CommandPermissions("worldedit.region.naturalize") @Logging(REGION) @Confirm(Confirm.Processor.REGION) + @SynchronousSettingExpected // TODO improve using filter/chunk-based-placement + @Preload(Preload.PreloadCheck.PRELOAD) public int naturalize(Actor actor, EditSession editSession, @Selection Region region) throws WorldEditException { int affected = editSession.naturalizeCuboidBlocks(region); actor.print(Caption.of("worldedit.naturalize.naturalized", TextComponent.of(affected))); @@ -437,6 +445,7 @@ public class RegionCommands { @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) @Confirm(Confirm.Processor.REGION) + @SynchronousSettingExpected public int smooth( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "# of iterations to perform", def = "1") @@ -452,7 +461,7 @@ public class RegionCommands { long volume = (((long) max.x() - (long) min.x() + 1) * ((long) max.y() - (long) min.y() + 1) * ((long) max.z() - (long) min .z() + 1)); FaweLimit limit = actor.getLimit(); - if (volume >= limit.MAX_CHECKS) { + if (volume >= limit.MAX_CHECKS.get()) { throw FaweCache.MAX_CHECKS; } int affected; @@ -510,6 +519,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.snowsmooth") @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int snowSmooth( Actor actor, EditSession editSession, @Selection Region region, @@ -536,6 +546,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.move") @Logging(ORIENTATION_REGION) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int move( Actor actor, World world, EditSession editSession, LocalSession session, @@ -599,6 +610,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.fall") @Logging(ORIENTATION_REGION) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public void fall( Actor actor, EditSession editSession, @@ -618,6 +630,7 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.stack") @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Logging(ORIENTATION_REGION) public int stack( Actor actor, World world, EditSession editSession, LocalSession session, @@ -683,6 +696,7 @@ public class RegionCommands { ) @CommandPermissions("worldedit.regen") @Logging(REGION) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) void regenerate( Actor actor, World world, LocalSession session, EditSession editSession, @@ -737,6 +751,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.deform") @Logging(ALL) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int deform( Actor actor, LocalSession session, EditSession editSession, @@ -814,6 +829,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.hollow") @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int hollow( Actor actor, EditSession editSession, @@ -848,6 +864,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.forest") @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int forest( Actor actor, EditSession editSession, @Selection Region region, @@ -869,6 +886,7 @@ public class RegionCommands { @CommandPermissions("worldedit.region.flora") @Logging(REGION) @Preload(Preload.PreloadCheck.PRELOAD) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int flora( Actor actor, EditSession editSession, @Selection Region region, 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 b98785631..074711521 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 @@ -28,6 +28,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.formatting.text.TextComponent; @@ -66,6 +67,7 @@ public class SnapshotUtilCommands { ) @Logging(REGION) @CommandPermissions("worldedit.snapshots.restore") + @SynchronousSettingExpected public void restore( Actor actor, World world, LocalSession session, EditSession editSession, @Arg(name = "snapshot", desc = "The snapshot to restore", def = "") 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 c81db21d8..c7c6ab9a1 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 @@ -44,6 +44,7 @@ import com.sk89q.worldedit.command.util.EntityRemover; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.PrintCommandHelp; import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; +import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; @@ -220,6 +221,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.fill") @Logging(PLACEMENT) + @SynchronousSettingExpected public int fill( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The blocks to fill with") @@ -311,6 +313,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.fill.recursive") @Logging(PLACEMENT) + @SynchronousSettingExpected public int fillr( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The blocks to fill with") @@ -343,6 +346,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.drain") @Logging(PLACEMENT) + @SynchronousSettingExpected public int drain( Actor actor, LocalSession session, EditSession editSession, //FAWE start - we take an expression over a double @@ -373,6 +377,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.fixlava") @Logging(PLACEMENT) + @SynchronousSettingExpected public int fixLava( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius to fix in") @@ -394,6 +399,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.fixwater") @Logging(PLACEMENT) + @SynchronousSettingExpected public int fixWater( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius to fix in") @@ -415,6 +421,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.removeabove") @Logging(PLACEMENT) + @SynchronousSettingExpected public int removeAbove( Actor actor, World world, LocalSession session, EditSession editSession, @Arg(desc = "The apothem of the square to remove from", def = "1") @@ -440,6 +447,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.removebelow") @Logging(PLACEMENT) + @SynchronousSettingExpected public int removeBelow( Actor actor, World world, LocalSession session, EditSession editSession, @Arg(desc = "The apothem of the square to remove from", def = "1") @@ -465,6 +473,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.removenear") @Logging(PLACEMENT) + @SynchronousSettingExpected public int removeNear( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The mask of blocks to remove") @@ -527,6 +536,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.snow") @Logging(PLACEMENT) + @SynchronousSettingExpected public int snow( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius of the cylinder to snow in", def = "10") @@ -566,6 +576,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.thaw") @Logging(PLACEMENT) + @SynchronousSettingExpected public int thaw( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius of the cylinder to thaw in", def = "10") @@ -595,6 +606,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.green") @Logging(PLACEMENT) + @SynchronousSettingExpected public int green( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius of the cylinder to convert in", def = "10") @@ -629,6 +641,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.extinguish") @Logging(PLACEMENT) + @SynchronousSettingExpected public int extinguish( Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius of the square to remove in", def = "") @@ -843,55 +856,6 @@ public class UtilityCommands { } } -// @Command( -// name = "/hollowr", -// desc = "Hollow out a space recursively with a pattern" -// ) -// @CommandPermissions("worldedit.hollowr") -// @Logging(PLACEMENT) -// public int hollowr( -// Actor actor, -// LocalSession session, -// EditSession editSession, -// @Arg(desc = "The radius to hollow out") Expression radiusExp, -// @ArgFlag(name = 'p', desc = "The blocks to fill with") Pattern pattern, -// @ArgFlag(name = 'm', desc = "The blocks remove", def = "") Mask mask -// ) throws WorldEditException { -// //FAWE start -// double radius = radiusExp.evaluate(); -// //FAWE end -// radius = Math.max(1, radius); -// we.checkMaxRadius(radius); -// if (mask == null) { -// Mask mask = new MaskIntersection( -// new RegionMask(new EllipsoidRegion(null, origin, Vector3.at(radius, radius, radius))), -// new BoundedHeightMask( -// Math.max(lowerBound, minY), -// Math.min(maxY, origin.getBlockY()) -// ), -// Masks.negate(new ExistingBlockMask(this)) -// ); -// } -// -// // Want to replace blocks -// BlockReplace replace = new BlockReplace(this, pattern); -// -// // Pick how we're going to visit blocks -// RecursiveVisitor visitor; -// //FAWE start - provide extent for preloading, min/max y -// if (recursive) { -// visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), minY, maxY, this); -// } else { -// visitor = new DownwardVisitor(mask, replace, origin.getBlockY(), (int) (radius * 2 + 1), minY, maxY, this); -// } -// //FAWE end -// -// BlockVector3 pos = session.getPlacementPosition(actor); -// int affected = editSession.res(pos, pattern, radius, depth, true); -// actor.print(Caption.of("worldedit.fillr.created", TextComponent.of(affected))); -// return affected; -// } - public static List> filesToEntry(final File root, final List files, final UUID uuid) { return files.stream() .map(input -> { // Keep this functional, as transform is evaluated lazily diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java index 2d35b2226..6a9a6fd95 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java @@ -89,7 +89,7 @@ public class BlockDataCyler implements DoubleActionBlockTool { Property objProp = (Property) currentProperty; BaseBlock newBlock = block.with(objProp, currentProperty.getValues().get(index)); - try (EditSession editSession = session.createEditSession(player)) { + try (EditSession editSession = session.createEditSession(player, null)) { try { editSession.setBlock(blockPoint, newBlock); player.print(Caption.of( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java index 75ef200c6..b37505d8b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java @@ -63,7 +63,7 @@ public class BlockReplacer implements DoubleActionBlockTool { ) { BlockBag bag = session.getBlockBag(player); - try (EditSession editSession = session.createEditSession(player)) { + try (EditSession editSession = session.createEditSession(player, null)) { try { BlockVector3 position = clicked.toVector().toBlockPoint(); editSession.setBlock(position, pattern); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java index b35865fb3..5cec2ec11 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java @@ -62,7 +62,7 @@ public class SinglePickaxe implements BlockTool { return false; } - try (EditSession editSession = session.createEditSession(player)) { + try (EditSession editSession = session.createEditSession(player, null)) { try { editSession.getSurvivalExtent().setToolUse(config.superPickaxeDrop); editSession.setBlock(blockPoint, BlockTypes.AIR.getDefaultState()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/StackTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/StackTool.java index 614bbcf32..415cade93 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/StackTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/StackTool.java @@ -59,7 +59,7 @@ public class StackTool implements BlockTool { } BlockBag bag = session.getBlockBag(player); - try (EditSession editSession = session.createEditSession(player)) { + try (EditSession editSession = session.createEditSession(player, null)) { BlockStateHolder block = editSession.getFullBlock(clicked.toVector().toBlockPoint()); try { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java index 1f52ff103..db92f6af9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java @@ -60,7 +60,7 @@ public class TreePlanter implements BlockTool { @Nullable Direction face ) { - try (EditSession editSession = session.createEditSession(player)) { + try (EditSession editSession = session.createEditSession(player, null)) { try { boolean successful = false; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java index 8efe2ab77..e38ae0d99 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java @@ -40,4 +40,15 @@ public interface Brush { */ void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException; + //FAWE start + /** + * If this brush is expected to set blocks synchronously, i.e. from one thread (at a time) + * + * @since TODO + */ + default boolean setsSynchronously() { + return true; + } + //FAWE end + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/ConfirmHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/ConfirmHandler.java index 067f9cfeb..5d6b66483 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/ConfirmHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/ConfirmHandler.java @@ -12,7 +12,7 @@ import java.lang.reflect.Method; import java.util.Optional; /** - * Logs called commands to a logger. + * Handles commands indicated as requiring confirmation. */ public class ConfirmHandler implements CommandCallListener { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/PreloadHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/PreloadHandler.java index 9e1dc106f..037c94e5b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/PreloadHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/PreloadHandler.java @@ -11,7 +11,7 @@ import java.lang.reflect.Method; import java.util.Optional; /** - * Logs called commands to a logger. + * Initialises preloading of chunks. */ public class PreloadHandler implements CommandCallListener { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/SynchronousSettingExpected.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/SynchronousSettingExpected.java new file mode 100644 index 000000000..3cc936fda --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/SynchronousSettingExpected.java @@ -0,0 +1,22 @@ +package com.sk89q.worldedit.command.util.annotation; + +import org.enginehub.piston.inject.InjectAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates it is expected that blocks will only be set synchronously, i.e. from one thread (at a time) + * + * @since TODO + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ + ElementType.METHOD +}) +@InjectAnnotation +public @interface SynchronousSettingExpected { + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/package-info.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/package-info.java index 006432a73..f7f293277 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/package-info.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/package-info.java @@ -8,6 +8,7 @@ * {@link com.sk89q.worldedit.command.util.annotation.PatternList}, * {@link com.sk89q.worldedit.command.util.annotation.Preload}, * {@link com.sk89q.worldedit.command.util.annotation.PreloadHandler}, + * {@link com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected}, * {@link com.sk89q.worldedit.command.util.annotation.Step}, * {@link com.sk89q.worldedit.command.util.annotation.Time} */ diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index b03e4ce54..65fc7c196 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -24,6 +24,7 @@ import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extension.platform.binding.Bindings; import com.fastasyncworldedit.core.extension.platform.binding.ConsumeBindings; +import com.fastasyncworldedit.core.extension.platform.binding.EditSessionHolder; import com.fastasyncworldedit.core.extension.platform.binding.PrimitiveBindings; import com.fastasyncworldedit.core.extension.platform.binding.ProvideBindings; import com.fastasyncworldedit.core.internal.command.MethodInjector; @@ -154,7 +155,6 @@ import org.enginehub.piston.inject.MemoizingValueAccess; import org.enginehub.piston.inject.MergedValueAccess; import org.enginehub.piston.part.SubCommandPart; import org.enginehub.piston.suggestion.Suggestion; -import org.enginehub.piston.util.HelpGenerator; import org.enginehub.piston.util.ValueProvider; import javax.annotation.Nonnull; @@ -227,7 +227,6 @@ public final class PlatformCommandManager { new ConfirmHandler(), new PreloadHandler() //FAWE end - )); // setup separate from main constructor // ensures that everything is definitely assigned @@ -312,20 +311,6 @@ public final class PlatformCommandManager { } ); //FAWE start - /* - globalInjectedValues.injectValue(Key.of(EditSession.class), - context -> { - LocalSession localSession = context.injectedValue(Key.of(LocalSession.class)) - .orElseThrow(() -> new IllegalStateException("No LocalSession")); - return context.injectedValue(Key.of(Actor.class)) - .map(actor -> { - EditSession editSession = localSession.createEditSession(actor); - editSession.enableStandardMode(); - Request.request().setEditSession(editSession); - return editSession; - }); - }); - */ // TODO: Ping @MattBDev to reimplement 2020-02-04 // globalInjectedValues.injectValue(Key.of(CFICommands.CFISettings.class), // context -> context.injectedValue(Key.of(Actor.class)) @@ -866,10 +851,10 @@ public final class PlatformCommandManager { store.injectValue(Key.of(InjectedValueStore.class), ValueProvider.constant(store)); store.injectValue(Key.of(Event.class), ValueProvider.constant(event)); //FAWE start - allow giving editsessions - if (event instanceof CommandEvent) { - EditSession session = ((CommandEvent) event).getSession(); + if (event instanceof CommandEvent commandEvent) { + EditSession session = commandEvent.getSession(); if (session != null) { - store.injectValue(Key.of(EditSession.class), context -> Optional.of(session)); + store.injectValue(Key.of(EditSessionHolder.class), context -> Optional.of(new EditSessionHolder(session))); } } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask.java index cd3ef56d5..ab919b35f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BiomeMask.java @@ -94,7 +94,7 @@ public class BiomeMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - BiomeType biome = getExtent().getBiome(vector); + BiomeType biome = vector.getBiome(getExtent()); return biomes.contains(biome); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java index bad9781ea..a1b869efb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java @@ -46,7 +46,7 @@ public class BlockCategoryMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - return category.contains(getExtent().getBlock(vector)); + return category.contains(vector.getBlock(getExtent())); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java index 9f191a4cc..c7d3473f3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java @@ -204,7 +204,7 @@ public class BlockMask extends ABlockMask { @Override public boolean test(BlockVector3 vector) { - int test = getExtent().getBlock(vector).getOrdinal(); + int test = vector.getBlock(getExtent()).getOrdinal(); return ordinals[test] || replacesAir() && test == 0; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java index ac558520c..0c563cdf7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockStateMask.java @@ -56,7 +56,7 @@ public class BlockStateMask extends AbstractExtentMask { //FAWE start @Override public boolean test(BlockVector3 vector) { - return test(getExtent().getBlock(vector)); + return test(vector.getBlock(getExtent())); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java index 17f1419e5..c3567b6d5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java @@ -124,7 +124,7 @@ public class BlockTypeMask extends AbstractExtentMask { //FAWE start @Override public boolean test(BlockVector3 vector) { - return test(getExtent().getBlock(vector).getBlockType()); + return test(vector.getBlock(getExtent()).getBlockType()); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java index b75a4cd1e..be62c2eae 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExistingBlockMask.java @@ -41,7 +41,7 @@ public class ExistingBlockMask extends AbstractExtentMask { @Override public boolean test(BlockVector3 vector) { - return !getExtent().getBlock(vector).getBlockType().getMaterial().isAir(); + return !vector.getBlock(getExtent()).getBlockType().getMaterial().isAir(); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java index e8b14b95a..6bb39b958 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockStateMask.java @@ -29,7 +29,7 @@ public class InverseSingleBlockStateMask extends ABlockMask { @Override public boolean test(BlockVector3 vector) { - int test = getExtent().getBlock(vector).getOrdinal(); + int test = vector.getBlock(getExtent()).getOrdinal(); if (isAir && test == 0) { return false; } diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index a56d98695..fea3e7dd5 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -141,6 +141,7 @@ "fawe.error.limit.max-brush-radius": "Maximum brush radius in limit: {0}", "fawe.error.limit.max-radius": "Maximum radius in limit: {0}", "fawe.error.no-valid-on-hotbar": "No valid block types on hotbar", + "fawe.error.no-process-non-synchronous-edit": "No processor holder was found but edit is non-synchronous", "fawe.cancel.count": "Cancelled {0} edits.", "fawe.cancel.reason.confirm": "Use //confirm to execute {0}", "fawe.cancel.reason.confirm.region": "Your selection is large ({0} -> {1}, containing {3} blocks). Use //confirm to execute {2}", @@ -151,6 +152,7 @@ "fawe.cancel.reason.low.memory": "Low memory", "fawe.cancel.reason.max.changes": "Too many blocks changed", "fawe.cancel.reason.max.checks": "Too many block checks", + "fawe.cancel.reason.max.fails": "Too many fails", "fawe.cancel.reason.max.tiles": "Too many block entities", "fawe.cancel.reason.max.entities": "Too many entities", "fawe.cancel.reason.max.iterations": "Max iterations", From 7e75ce78ec2b2383659cb6a1ac1eb0eb6193a8cc Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Wed, 18 Sep 2024 23:04:56 +0200 Subject: [PATCH 388/466] Fix tile copying (#2922) --- .../clipboard/DiskOptimizedClipboard.java | 36 +++++++++---------- .../extent/clipboard/LinearClipboard.java | 4 +++ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java index c81059ccb..dc2ba4505 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java @@ -10,6 +10,7 @@ import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.util.MainUtil; import com.fastasyncworldedit.core.util.NbtUtils; import com.fastasyncworldedit.core.util.ReflectionUtils; +import com.google.common.collect.Collections2; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.DoubleTag; import com.sk89q.jnbt.ListTag; @@ -30,6 +31,8 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypesCache; import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinTagType; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; @@ -66,8 +69,7 @@ public class DiskOptimizedClipboard extends LinearClipboard { private static final int VERSION_2_HEADER_SIZE = 27; // Header size of "version 2" i.e. when NBT/entities could be saved private static final Map LOCK_HOLDER_CACHE = new ConcurrentHashMap<>(); - private final HashMap nbtMap; - private final HashMap nbtMap2; + private final HashMap nbtMap; private final File file; private final int headerSize; @@ -127,7 +129,6 @@ public class DiskOptimizedClipboard extends LinearClipboard { canHaveBiomes = false; } nbtMap = new HashMap<>(); - nbtMap2 = new HashMap<>(); try { this.file = file; try { @@ -184,7 +185,6 @@ public class DiskOptimizedClipboard extends LinearClipboard { super(readSize(file, versionOverride), BlockVector3.ZERO); headerSize = getHeaderSizeOverrideFromVersion(versionOverride); nbtMap = new HashMap<>(); - nbtMap2 = new HashMap<>(); try { this.file = file; this.braf = new RandomAccessFile(file, "rw"); @@ -253,12 +253,12 @@ public class DiskOptimizedClipboard extends LinearClipboard { try (NBTInputStream nbtIS = new NBTInputStream(MainUtil.getCompressedIS(new ByteBufferInputStream(tmp)))) { Iterator iter = nbtIS.toIterator(); while (nbtCount > 0 && iter.hasNext()) { // TileEntities are stored "before" entities - CompoundTag tag = iter.next(); - int x = tag.getInt("x"); - int y = tag.getInt("y"); - int z = tag.getInt("z"); + LinCompoundTag tag = iter.next().toLinTag(); + int x = tag.getTag("x", LinTagType.intTag()).valueAsInt(); + int y = tag.getTag("y", LinTagType.intTag()).valueAsInt(); + int z = tag.getTag("z", LinTagType.intTag()).valueAsInt(); IntTriple pos = new IntTriple(x, y, z); - nbtMap.put(pos, tag); + nbtMap.put(pos, FaweCompoundTag.of(tag)); nbtCount--; } while (entitiesCount > 0 && iter.hasNext()) { @@ -564,8 +564,8 @@ public class DiskOptimizedClipboard extends LinearClipboard { ))) { if (!nbtMap.isEmpty()) { try { - for (CompoundTag tag : nbtMap.values()) { - nbtOS.writeTag(tag); + for (FaweCompoundTag tag : nbtMap.values()) { + nbtOS.writeTag(new CompoundTag(tag.linTag())); } } catch (IOException e) { e.printStackTrace(); @@ -643,7 +643,7 @@ public class DiskOptimizedClipboard extends LinearClipboard { @Override public Collection getTileEntities() { - return nbtMap.values(); + return Collections2.transform(nbtMap.values(), fct -> new CompoundTag(fct.linTag())); } public int getIndex(int x, int y, int z) { @@ -661,10 +661,10 @@ public class DiskOptimizedClipboard extends LinearClipboard { private BaseBlock toBaseBlock(BlockState state, int i) { if (state.getMaterial().hasContainer() && !nbtMap.isEmpty()) { - CompoundTag nbt; + FaweCompoundTag nbt; if (nbtMap.size() < 4) { nbt = null; - for (Map.Entry entry : nbtMap.entrySet()) { + for (Map.Entry entry : nbtMap.entrySet()) { IntTriple key = entry.getKey(); int index = getIndex(key.x(), key.y(), key.z()); if (index == i) { @@ -679,15 +679,15 @@ public class DiskOptimizedClipboard extends LinearClipboard { int x = newI - z * getWidth(); nbt = nbtMap.get(new IntTriple(x, y, z)); } - return state.toBaseBlock(nbt); + return state.toBaseBlock(nbt == null ? null : nbt.linTag()); } return state.toBaseBlock(); } private BaseBlock toBaseBlock(BlockState state, int x, int y, int z) { if (state.getMaterial().hasContainer() && !nbtMap.isEmpty()) { - CompoundTag nbt = nbtMap.get(new IntTriple(x, y, z)); - return state.toBaseBlock(nbt); + FaweCompoundTag nbt = nbtMap.get(new IntTriple(x, y, z)); + return state.toBaseBlock(nbt == null ? null : nbt.linTag()); } return state.toBaseBlock(); } @@ -715,7 +715,7 @@ public class DiskOptimizedClipboard extends LinearClipboard { @Override public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tile) throws WorldEditException { - nbtMap2.put(new IntTriple(x, y, z), NbtUtils.withPosition(tile, x, y, z)); + nbtMap.put(new IntTriple(x, y, z), NbtUtils.withPosition(tile, x, y, z)); return true; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java index 2e65f59ca..cc0bb07f6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java @@ -57,6 +57,10 @@ public abstract class LinearClipboard extends SimpleClipboard { */ public abstract void streamBiomes(IntValueReader task); + /** + * @deprecated will be removed as it is unused and uses outdated types + */ + @Deprecated(forRemoval = true, since = "TODO") public abstract Collection getTileEntities(); @Override From 393f80165c3bbeb1e5cef625811825140e6f5d90 Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 19 Sep 2024 05:55:53 +0100 Subject: [PATCH 389/466] fix: add timeout to reading history from exchanger (#2920) --- .../core/history/changeset/ChangeExchangeCoordinator.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/ChangeExchangeCoordinator.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/ChangeExchangeCoordinator.java index 2f3398a60..3c020d422 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/ChangeExchangeCoordinator.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/ChangeExchangeCoordinator.java @@ -4,6 +4,8 @@ import com.sk89q.worldedit.history.change.Change; import org.jetbrains.annotations.ApiStatus; import java.util.concurrent.Exchanger; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.function.BiConsumer; /** @@ -32,8 +34,9 @@ public class ChangeExchangeCoordinator implements AutoCloseable { .start(() -> this.runnerTask.accept(this.exchanger, new Change[length])); } try { - return exchanger.exchange(consumed); - } catch (InterruptedException e) { + // Allow a reasonable timeout in case of weirdness + return exchanger.exchange(consumed, 30, TimeUnit.SECONDS); + } catch (InterruptedException | TimeoutException e) { this.runner.interrupt(); Thread.currentThread().interrupt(); return null; From 7daafa97f03e0f79baf1996b1ad9c79f7bcfb686 Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 20 Sep 2024 23:10:39 +0100 Subject: [PATCH 390/466] fix: adjust linked filter to be left-right and do not link to new forked instances (#2913) * fix: adjust linked filter to be left-right and do not link to new forked instances - Assume that child filters know about their own forks - fixes #1874 * Remove appliesChunk|Layer for now --- .../core/extent/filter/LinkedFilter.java | 83 ++++++++++++------- .../extent/filter/block/ChunkFilterBlock.java | 12 ++- .../fastasyncworldedit/core/queue/Filter.java | 36 ++++---- .../core/queue/IDelegateFilter.java | 10 --- .../core/queue/IQueueExtent.java | 6 +- .../implementation/ParallelQueueExtent.java | 3 +- .../com/sk89q/worldedit/regions/Region.java | 12 ++- 7 files changed, 93 insertions(+), 69 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/LinkedFilter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/LinkedFilter.java index a600fc180..26700ccc5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/LinkedFilter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/LinkedFilter.java @@ -1,69 +1,92 @@ package com.fastasyncworldedit.core.extent.filter; -import com.fastasyncworldedit.core.extent.filter.block.DelegateFilter; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; import com.fastasyncworldedit.core.internal.simd.VectorizedFilter; import com.fastasyncworldedit.core.queue.Filter; +import com.fastasyncworldedit.core.queue.IChunk; +import com.sk89q.worldedit.regions.Region; import jdk.incubator.vector.ShortVector; +import org.jetbrains.annotations.Nullable; /** - * Filter which links two Filters together for single-filter-input operations. + * Filter which links two Filters together for single-filter-input operations. Left filter is operated first. * - * @param Parent which extends Filter - * @param Child which extends Filter + * @param Left filter + * @param Right filter */ -public sealed class LinkedFilter extends DelegateFilter { +public sealed class LinkedFilter implements Filter { - private final S child; + private final L left; + private final R right; + + public LinkedFilter(L left, R right) { + this.left = left; + this.right = right; + } @SuppressWarnings({"unchecked", "rawtypes"}) // we defeated the type system - public static LinkedFilter of(T parent, S child) { - if (parent instanceof VectorizedFilter p && child instanceof VectorizedFilter c) { - return new VectorizedLinkedFilter(p, c); + public static LinkedFilter of(L left, R right) { + if (left instanceof VectorizedFilter l && right instanceof VectorizedFilter r) { + return new VectorizedLinkedFilter(l, r); } - return new LinkedFilter<>(parent, child); + return new LinkedFilter<>(left, right); } - public LinkedFilter(T parent, S child) { - super(parent); - this.child = child; + public L getLeft() { + return this.left; } - public S getChild() { - return this.child; + public R getRight() { + return this.right; + } + + @Override + public T applyChunk(T chunk, @Nullable Region region) { + chunk = getLeft().applyChunk(chunk, region); + return getRight().applyChunk(chunk, region); } @Override public void applyBlock(FilterBlock block) { - this.getParent().applyBlock(block); - this.getChild().applyBlock(block); + getLeft().applyBlock(block); + getRight().applyBlock(block); } @Override - public LinkedFilter, ? extends Filter> newInstance(Filter other) { - return new LinkedFilter<>(this, other); + public void finishChunk(IChunk chunk) { + getLeft().finishChunk(chunk); + getRight().finishChunk(chunk); } - private final static class VectorizedLinkedFilter - extends LinkedFilter implements VectorizedFilter { + @Override + public Filter fork() { + return new LinkedFilter<>(getLeft().fork(), getRight().fork()); + } - public VectorizedLinkedFilter(final T parent, final S child) { - super(parent, child); + @Override + public void join() { + getLeft().join(); + getRight().join(); + } + + private final static class VectorizedLinkedFilter + extends LinkedFilter implements VectorizedFilter { + + public VectorizedLinkedFilter(final L left, final R right) { + super(left, right); } @Override public ShortVector applyVector(final ShortVector get, final ShortVector set) { - ShortVector res = getParent().applyVector(get, set); - return getChild().applyVector(get, res); + ShortVector res = getLeft().applyVector(get, set); + return getRight().applyVector(get, res); } @Override - public LinkedFilter, Filter> newInstance(Filter other) { - if (other instanceof VectorizedFilter o) { - return new VectorizedLinkedFilter(this, o); - } - return new LinkedFilter<>(this, other); + public Filter fork() { + return new VectorizedLinkedFilter<>((L) getLeft().fork(), (R) getRight().fork()); } + } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/ChunkFilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/ChunkFilterBlock.java index 9e11021d2..830ff9ab1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/ChunkFilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/ChunkFilterBlock.java @@ -83,12 +83,20 @@ public abstract class ChunkFilterBlock extends AbstractExtentFilterBlock { /** * Filter a chunk with a region / filter. */ - public synchronized final IChunkSet filter(IChunk chunk, IChunkGet get, IChunkSet set, Filter filter, Region region, boolean full) { + public synchronized final IChunkSet filter( + IChunk chunk, + IChunkGet get, + IChunkSet set, + Filter filter, + Region region, + boolean full + ) { if (region != null) { region.filter(chunk, filter, this, get, set, full); } else { for (int layer = get.getMinSectionPosition(); layer <= get.getMaxSectionPosition(); layer++) { - if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + //if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + if (!full && !get.hasSection(layer)) { continue; } initLayer(get, set, layer); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/Filter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/Filter.java index 366faa8c5..f308d4806 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/Filter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/Filter.java @@ -3,6 +3,7 @@ package com.fastasyncworldedit.core.queue; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; import com.sk89q.worldedit.regions.Region; +import javax.annotation.Nonnull; import javax.annotation.Nullable; /** @@ -10,30 +11,29 @@ import javax.annotation.Nullable; */ public interface Filter { - /** - * Checks whether a chunk should be read. - * - * @param chunkX the x coordinate in the chunk - * @param chunkZ the z coordinate in the chunk - */ - default boolean appliesChunk( - int chunkX, - int chunkZ - ) { - return true; - } +// /** +// * Checks whether a chunk should be read. +// * +// * @param chunkX the x coordinate in the chunk +// * @param chunkZ the z coordinate in the chunk +// */ +// default boolean appliesChunk( +// int chunkX, +// int chunkZ +// ) { +// return true; +// } /** - * Do something with the IChunk
    - Return null if you don't want to filter blocks
    - - * Return the chunk if you do want to filter blocks
    + * Do something with the IChunk
    */ - default T applyChunk(T chunk, @Nullable Region region) { + default @Nonnull T applyChunk(T chunk, @Nullable Region region) { return chunk; } - default boolean appliesLayer(IChunk chunk, int layer) { - return true; - } +// default boolean appliesLayer(IChunk chunk, int layer) { +// return true; +// } /** * Make changes to the block here
    - e.g., block.setId(...)
    - Note: Performance is diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IDelegateFilter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IDelegateFilter.java index a4bb54017..1e172dd19 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IDelegateFilter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IDelegateFilter.java @@ -9,21 +9,11 @@ public interface IDelegateFilter extends Filter { Filter getParent(); - @Override - default boolean appliesChunk(int chunkX, int chunkZ) { - return getParent().appliesChunk(chunkX, chunkZ); - } - @Override default V applyChunk(V chunk, @Nullable Region region) { return getParent().applyChunk(chunk, region); } - @Override - default boolean appliesLayer(IChunk chunk, int layer) { - return getParent().appliesLayer(chunk, layer); - } - @Override default void applyBlock(FilterBlock block) { getParent().applyBlock(block); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java index ee3740411..d09b7f04b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java @@ -140,9 +140,9 @@ public interface IQueueExtent extends Flushable, Trimable, ICh int chunkZ, boolean full ) { - if (!filter.appliesChunk(chunkX, chunkZ)) { - return block; - } +// if (!filter.appliesChunk(chunkX, chunkZ)) { +// return block; +// } T chunk = this.getOrCreateChunk(chunkX, chunkZ); T newChunk = filter.applyChunk(chunk, region); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java index f197524f3..56a238166 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java @@ -30,7 +30,6 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.world.World; @@ -227,7 +226,7 @@ public class ParallelQueueExtent extends PassthroughExtent { public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException { VectorizedFilter vectorizedPattern = SimdSupport.vectorizedPattern(pattern); var filter = LinkedFilter.of(vectorizedPattern == null ? pattern : vectorizedPattern, new CountFilter()); - return this.changes = apply(region, filter, true).getChild().getTotal(); + return this.changes = apply(region, filter, true).getRight().getTotal(); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java index 085274772..c236992cf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java @@ -269,7 +269,8 @@ public interface Region extends Iterable, Cloneable, IBatchProcess int minSection = Math.max(get.getMinSectionPosition(), getMinimumY() >> 4); int maxSection = Math.min(get.getMaxSectionPosition(), getMaximumY() >> 4); for (int layer = minSection; layer <= maxSection; layer++) { - if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + //if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + if (!full && !get.hasSection(layer)) { return; } block = block.initLayer(get, set, layer); @@ -319,7 +320,8 @@ public interface Region extends Iterable, Cloneable, IBatchProcess int layer, boolean full ) { - if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + //if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + if (!full && !get.hasSection(layer)) { return; } block = block.initLayer(get, set, layer); @@ -341,7 +343,8 @@ public interface Region extends Iterable, Cloneable, IBatchProcess int maxZ, boolean full ) { - if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + //if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + if (!full && !get.hasSection(layer)) { return; } block = block.initLayer(get, set, layer); @@ -359,7 +362,8 @@ public interface Region extends Iterable, Cloneable, IBatchProcess int yEnd, boolean full ) { - if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + //if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + if (!full && !get.hasSection(layer)) { return; } block = block.initLayer(get, set, layer); From 8e1922dfe7841575c6b6136cb706006238cfccd2 Mon Sep 17 00:00:00 2001 From: Tyler Resch Date: Sun, 22 Sep 2024 16:41:38 -0400 Subject: [PATCH 391/466] fix: apply origin to sponge v3 schematics (#2909) * fix(#2864) * Cherry-picked EngineHub/WorldEdit@cfd9eea Co-authored-by: Pierre Maurice Schwang * Allow metadata tags to be optional + default value for this.origin Co-authored-by: Pierre Maurice Schwang * Correct depth to be default of `0` Co-authored-by: Pierre Maurice Schwang --------- Co-authored-by: Pierre Maurice Schwang --- .../clipboard/io/FastSchematicReaderV3.java | 23 ++++++++++++++++++- .../io/sponge/SpongeSchematicV3Reader.java | 2 +- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java index 55e249740..0e48f32d0 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java @@ -41,6 +41,8 @@ import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinTagType; import org.jetbrains.annotations.ApiStatus; import java.io.BufferedInputStream; @@ -88,6 +90,7 @@ public class FastSchematicReaderV3 implements ClipboardReader { private VersionedDataFixer dataFixer; private BlockVector3 offset; + private BlockVector3 origin = BlockVector3.ZERO; private BlockState[] blockPalette; private BiomeType[] biomePalette; private int dataVersion = -1; @@ -137,6 +140,24 @@ public class FastSchematicReaderV3 implements ClipboardReader { this.dataVersion = this.dataInputStream.readInt(); this.dataFixer = ReaderUtil.getVersionedDataFixer(this.dataVersion, platform, platform.getDataVersion()); } + case "Metadata" -> { + LinCompoundTag metadataCompoundTag = + (LinCompoundTag) this.nbtInputStream.readTagPayload(NBTConstants.TYPE_COMPOUND, 0).toLinTag(); + + LinCompoundTag worldEditTag = metadataCompoundTag.findTag("WorldEdit", LinTagType.compoundTag()); + if (worldEditTag != null) { // allowed to be optional + LinIntArrayTag originTag = worldEditTag.findTag("Origin", LinTagType.intArrayTag()); + if (originTag != null) { // allowed to be optional + int[] parts = originTag.value(); + + if (parts.length != 3) { + throw new IOException("`Metadata > WorldEdit > Origin` int array length is invalid."); + } + + this.origin = BlockVector3.at(parts[0], parts[1], parts[2]); + } + } + } case "Offset" -> { this.dataInputStream.skipNBytes(4); // Array Length field (4 byte int) this.offset = BlockVector3.at( @@ -173,7 +194,7 @@ public class FastSchematicReaderV3 implements ClipboardReader { clipboard.setOrigin(this.offset.multiply(-1)); if (clipboard instanceof SimpleClipboard simpleClipboard && !this.offset.equals(BlockVector3.ZERO)) { - clipboard = new BlockArrayClipboard(simpleClipboard, this.offset); + clipboard = new BlockArrayClipboard(simpleClipboard, this.offset.add(this.origin)); } return clipboard; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Reader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Reader.java index 978cb8ba5..15032be82 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Reader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Reader.java @@ -135,7 +135,7 @@ public class SpongeSchematicV3Reader implements ClipboardReader { Map palette = ReaderUtil.decodePalette(paletteObject, fixer); byte[] blocks = blockContainer.getTag("Data", LinTagType.byteArrayTag()).value(); - LinListTag blockEntities = blockContainer.getListTag("BlockEntities", LinTagType.compoundTag()); + LinListTag blockEntities = blockContainer.findListTag("BlockEntities", LinTagType.compoundTag()); ReaderUtil.initializeClipboardFromBlocks(clipboard, palette, blocks, blockEntities, fixer, true); } From 24c2ef2321b9895268532e2e93ce815dab445a70 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 01:14:22 +0000 Subject: [PATCH 392/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.4.3 (#2924) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3927910c9..11f6551d2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.4.1" +towny = "0.100.4.3" plotsquared = "7.3.10" # Third party From f22f9abf49461a929c03c33b612a9f70b50797b0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 01:15:00 +0000 Subject: [PATCH 393/466] Update dependency com.gradleup.shadow:shadow-gradle-plugin to v8.3.2 (#2923) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index b4d03430f..5735dc56c 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -23,7 +23,7 @@ val properties = Properties().also { props -> dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2") - implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.1") + implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.2") implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.2") constraints { val asmVersion = "[9.7,)" From 9ad6ff77536bc4b211a4d920ce0d503be4fc9517 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 03:11:20 +0000 Subject: [PATCH 394/466] Update plotsquared to v7.3.11 (#2926) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 11f6551d2..64ae0731e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" towny = "0.100.4.3" -plotsquared = "7.3.10" +plotsquared = "7.3.11" # Third party bstats = "3.0.3" From 5ac60f0d2ed4772870dbf2f385e623cfb22e5098 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 03:11:40 +0000 Subject: [PATCH 395/466] Update dependency paperweight-userdev (#2925) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts | 2 +- worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts index 6aac6f9d9..1642d5a51 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/ - the().paperDevBundle("1.20.6-R0.1-20240824.093908-124") + the().paperDevBundle("1.20.6-R0.1-20240916.192025-125") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts index 4eb949758..fce133358 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.1-R0.1-20240910.023150-72") + the().paperDevBundle("1.21.1-R0.1-20240922.215204-93") compileOnly(libs.paperlib) } From b4635e85c9ab3c300644f28b7a217d89d96a831b Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 25 Sep 2024 18:20:49 +0100 Subject: [PATCH 396/466] fix: some improvements to GET chunk writing (#2853) * fix: some improvements to GET chunk writing - ensure levelChunk is loaded before giving to copy GET - this is not necessarily guaranteed to be nonnull if two edits overlap. Whilst not advised, such an easy failure should not occur when two edits collide * Prevent writing chunk sections when FAWE is also sending packets for a chunk and vice versa - alter IntPair hashcode to be more often unique - Utilise ConcurrentHashMap for free synchronisation * Minor comment changes * Use one-per-world-instance FaweBukkitWorld to store world chunk map --- .../fawe/v1_20_R2/PaperweightGetBlocks.java | 34 ++--- .../v1_20_R2/PaperweightPlatformAdapter.java | 56 +++++---- .../PaperweightStarlightRelighter.java | 3 +- .../fawe/v1_20_R3/PaperweightGetBlocks.java | 34 ++--- .../v1_20_R3/PaperweightPlatformAdapter.java | 56 +++++---- .../PaperweightStarlightRelighter.java | 3 +- .../fawe/v1_20_R4/PaperweightGetBlocks.java | 38 +++--- .../v1_20_R4/PaperweightPlatformAdapter.java | 64 ++++++---- .../PaperweightStarlightRelighter.java | 3 +- .../fawe/v1_21_R1/PaperweightGetBlocks.java | 38 +++--- .../v1_21_R1/PaperweightPlatformAdapter.java | 65 ++++++---- .../PaperweightStarlightRelighter.java | 3 +- .../bukkit/FaweBukkitWorld.java | 67 ++++++++++ .../bukkit/adapter/NMSAdapter.java | 119 ++++++++++++++++++ .../sk89q/worldedit/bukkit/BukkitWorld.java | 4 +- .../fastasyncworldedit/core/math/IntPair.java | 4 +- 16 files changed, 425 insertions(+), 166 deletions(-) create mode 100644 worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/FaweBukkitWorld.java diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java index 4bcdee27d..a325bb08b 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java @@ -7,6 +7,7 @@ import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; @@ -106,6 +107,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private final ServerLevel serverLevel; private final int chunkX; private final int chunkZ; + private final IntPair chunkPos; private final int minHeight; private final int maxHeight; private final int minSectionPosition; @@ -140,6 +142,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc this.blockLight = new DataLayer[getSectionCount()]; this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME); this.biomeHolderIdMap = biomeRegistry.asHolderIdMap(); + this.chunkPos = new IntPair(chunkX, chunkZ); } public int getChunkX() { @@ -425,7 +428,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked."); } forceLoadSections = false; - PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; + LevelChunk nmsChunk = ensureLoaded(serverLevel, chunkX, chunkZ); + PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(nmsChunk) : null; if (createCopy) { if (copies.containsKey(copyKey)) { throw new IllegalStateException("Copy key already used."); @@ -433,9 +437,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc copies.put(copyKey, copy); } try { - ServerLevel nmsWorld = serverLevel; - LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); - // Remove existing tiles. Create a copy so that we can remove blocks Map chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); List beacons = null; @@ -507,6 +508,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc biomeData ); if (PaperweightPlatformAdapter.setSectionAtomic( + serverLevel.getWorld().getName(), + chunkPos, levelChunkSections, null, newSection, @@ -584,6 +587,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc biomeData ); if (PaperweightPlatformAdapter.setSectionAtomic( + serverLevel.getWorld().getName(), + chunkPos, levelChunkSections, null, newSection, @@ -649,6 +654,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() ); if (!PaperweightPlatformAdapter.setSectionAtomic( + serverLevel.getWorld().getName(), + chunkPos, levelChunkSections, existingSection, newSection, @@ -722,7 +729,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { for (UUID uuid : entityRemoves) { - Entity entity = nmsWorld.getEntities().get(uuid); + Entity entity = serverLevel.getEntities().get(uuid); if (entity != null) { removeEntity(entity); } @@ -761,7 +768,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc EntityType type = EntityType.byString(id).orElse(null); if (type != null) { - Entity entity = type.create(nmsWorld); + Entity entity = type.create(serverLevel); if (entity != null) { final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(linTag); for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { @@ -770,11 +777,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc entity.load(tag); entity.absMoveTo(x, y, z, yaw, pitch); entity.setUUID(NbtUtils.uuid(nativeTag)); - if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { + if (!serverLevel.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { LOGGER.warn( "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", id, - nmsWorld.getWorld().getName(), + serverLevel.getWorld().getName(), x, y, z @@ -804,11 +811,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc final int z = blockHash.z() + bz; final BlockPos pos = new BlockPos(x, y, z); - synchronized (nmsWorld) { - BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); + synchronized (serverLevel) { + BlockEntity tileEntity = serverLevel.getBlockEntity(pos); if (tileEntity == null || tileEntity.isRemoved()) { - nmsWorld.removeBlockEntity(pos); - tileEntity = nmsWorld.getBlockEntity(pos); + serverLevel.removeBlockEntity(pos); + tileEntity = serverLevel.getBlockEntity(pos); } if (tileEntity != null) { final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag()); @@ -827,7 +834,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc callback = null; } else { int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; - boolean finalLightUpdate = lightUpdate; callback = () -> { // Set Modified nmsChunk.setLightCorrect(true); // Set Modified @@ -933,7 +939,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public void send() { synchronized (sendLock) { - PaperweightPlatformAdapter.sendChunk(this, serverLevel, chunkX, chunkZ); + PaperweightPlatformAdapter.sendChunk(new IntPair(chunkX, chunkZ), serverLevel, chunkX, chunkZ); } } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java index a56548c46..d7fab2dd6 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java @@ -7,8 +7,8 @@ import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.ReflectionUtils; import com.fastasyncworldedit.core.util.TaskManager; import com.mojang.datafixers.util.Either; import com.sk89q.worldedit.bukkit.WorldEditPlugin; @@ -243,15 +243,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } static boolean setSectionAtomic( + String worldName, + IntPair pair, LevelChunkSection[] sections, LevelChunkSection expected, LevelChunkSection value, int layer ) { - if (layer >= 0 && layer < sections.length) { - return ReflectionUtils.compareAndSet(sections, expected, value, layer); - } - return false; + return NMSAdapter.setSectionAtomic(worldName, pair, sections, expected, value, layer); } // There is no point in having a functional semaphore for paper servers. @@ -349,7 +348,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } @SuppressWarnings("deprecation") - public static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int chunkZ) { + public static void sendChunk(IntPair pair, ServerLevel nmsWorld, int chunkX, int chunkZ) { ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); if (chunkHolder == null) { return; @@ -370,26 +369,35 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { if (levelChunk == null) { return; } + StampLockHolder lockHolder = new StampLockHolder(); + NMSAdapter.beginChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder); + if (lockHolder.chunkLock == null) { + return; + } MinecraftServer.getServer().execute(() -> { - ClientboundLevelChunkWithLightPacket packet; - if (PaperLib.isPaper()) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - false // last false is to not bother with x-ray - ); - } else { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); + try { + ClientboundLevelChunkWithLightPacket packet; + if (PaperLib.isPaper()) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); + } else { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); + } + nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); + } finally { + NMSAdapter.endChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder); } - nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java index addf03867..b92835a82 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java @@ -2,6 +2,7 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.queue.IQueueExtent; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; @@ -67,7 +68,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); List beacons = null; @@ -507,6 +508,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc biomeData ); if (PaperweightPlatformAdapter.setSectionAtomic( + serverLevel.getWorld().getName(), + chunkPos, levelChunkSections, null, newSection, @@ -584,6 +587,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc biomeData ); if (PaperweightPlatformAdapter.setSectionAtomic( + serverLevel.getWorld().getName(), + chunkPos, levelChunkSections, null, newSection, @@ -649,6 +654,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() ); if (!PaperweightPlatformAdapter.setSectionAtomic( + serverLevel.getWorld().getName(), + chunkPos, levelChunkSections, existingSection, newSection, @@ -722,7 +729,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { for (UUID uuid : entityRemoves) { - Entity entity = nmsWorld.getEntities().get(uuid); + Entity entity = serverLevel.getEntities().get(uuid); if (entity != null) { removeEntity(entity); } @@ -761,7 +768,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc EntityType type = EntityType.byString(id).orElse(null); if (type != null) { - Entity entity = type.create(nmsWorld); + Entity entity = type.create(serverLevel); if (entity != null) { final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(linTag); for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { @@ -770,11 +777,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc entity.load(tag); entity.absMoveTo(x, y, z, yaw, pitch); entity.setUUID(NbtUtils.uuid(nativeTag)); - if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { + if (!serverLevel.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { LOGGER.warn( "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", id, - nmsWorld.getWorld().getName(), + serverLevel.getWorld().getName(), x, y, z @@ -804,11 +811,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc final int z = blockHash.z() + bz; final BlockPos pos = new BlockPos(x, y, z); - synchronized (nmsWorld) { - BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); + synchronized (serverLevel) { + BlockEntity tileEntity = serverLevel.getBlockEntity(pos); if (tileEntity == null || tileEntity.isRemoved()) { - nmsWorld.removeBlockEntity(pos); - tileEntity = nmsWorld.getBlockEntity(pos); + serverLevel.removeBlockEntity(pos); + tileEntity = serverLevel.getBlockEntity(pos); } if (tileEntity != null) { final net.minecraft.nbt.CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag()); @@ -827,7 +834,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc callback = null; } else { int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; - boolean finalLightUpdate = lightUpdate; callback = () -> { // Set Modified nmsChunk.setLightCorrect(true); // Set Modified @@ -932,7 +938,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public void send() { - PaperweightPlatformAdapter.sendChunk(this, serverLevel, chunkX, chunkZ); + PaperweightPlatformAdapter.sendChunk(new IntPair(chunkX, chunkZ), serverLevel, chunkX, chunkZ); } /** diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java index 76cc25e02..2c05d7466 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java @@ -7,8 +7,8 @@ import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.ReflectionUtils; import com.fastasyncworldedit.core.util.TaskManager; import com.mojang.datafixers.util.Either; import com.sk89q.worldedit.bukkit.WorldEditPlugin; @@ -243,15 +243,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } static boolean setSectionAtomic( + String worldName, + IntPair pair, LevelChunkSection[] sections, LevelChunkSection expected, LevelChunkSection value, int layer ) { - if (layer >= 0 && layer < sections.length) { - return ReflectionUtils.compareAndSet(sections, expected, value, layer); - } - return false; + return NMSAdapter.setSectionAtomic(worldName, pair, sections, expected, value, layer); } // There is no point in having a functional semaphore for paper servers. @@ -349,7 +348,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } @SuppressWarnings("deprecation") - public static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int chunkZ) { + public static void sendChunk(IntPair pair, ServerLevel nmsWorld, int chunkX, int chunkZ) { ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); if (chunkHolder == null) { return; @@ -370,26 +369,35 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { if (levelChunk == null) { return; } + StampLockHolder lockHolder = new StampLockHolder(); + NMSAdapter.beginChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder); + if (lockHolder.chunkLock == null) { + return; + } MinecraftServer.getServer().execute(() -> { - ClientboundLevelChunkWithLightPacket packet; - if (PaperLib.isPaper()) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - false // last false is to not bother with x-ray - ); - } else { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); + try { + ClientboundLevelChunkWithLightPacket packet; + if (PaperLib.isPaper()) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); + } else { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); + } + nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); + } finally { + NMSAdapter.endChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder); } - nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); } diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java index d9109b4df..a1ce327f9 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java @@ -2,6 +2,7 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.queue.IQueueExtent; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; @@ -67,7 +68,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); List beacons = null; @@ -508,6 +509,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc biomeData ); if (PaperweightPlatformAdapter.setSectionAtomic( + serverLevel.getWorld().getName(), + chunkPos, levelChunkSections, null, newSection, @@ -585,6 +588,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc biomeData ); if (PaperweightPlatformAdapter.setSectionAtomic( + serverLevel.getWorld().getName(), + chunkPos, levelChunkSections, null, newSection, @@ -649,7 +654,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc biomeRegistry, biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() ); - if (!PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, existingSection, + if (!PaperweightPlatformAdapter.setSectionAtomic( + serverLevel.getWorld().getName(), + chunkPos, + levelChunkSections, + existingSection, newSection, getSectionIndex )) { @@ -721,7 +730,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { for (UUID uuid : entityRemoves) { - Entity entity = nmsWorld.getEntities().get(uuid); + Entity entity = serverLevel.getEntities().get(uuid); if (entity != null) { removeEntity(entity); } @@ -760,7 +769,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc EntityType type = EntityType.byString(id).orElse(null); if (type != null) { - Entity entity = type.create(nmsWorld); + Entity entity = type.create(serverLevel); if (entity != null) { final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(linTag); for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { @@ -769,11 +778,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc entity.load(tag); entity.absMoveTo(x, y, z, yaw, pitch); entity.setUUID(NbtUtils.uuid(nativeTag)); - if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { + if (!serverLevel.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { LOGGER.warn( "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", id, - nmsWorld.getWorld().getName(), + serverLevel.getWorld().getName(), x, y, z @@ -803,11 +812,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc final int z = blockHash.z() + bz; final BlockPos pos = new BlockPos(x, y, z); - synchronized (nmsWorld) { - BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); + synchronized (serverLevel) { + BlockEntity tileEntity = serverLevel.getBlockEntity(pos); if (tileEntity == null || tileEntity.isRemoved()) { - nmsWorld.removeBlockEntity(pos); - tileEntity = nmsWorld.getBlockEntity(pos); + serverLevel.removeBlockEntity(pos); + tileEntity = serverLevel.getBlockEntity(pos); } if (tileEntity != null) { final net.minecraft.nbt.CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag()); @@ -826,7 +835,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc callback = null; } else { int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; - boolean finalLightUpdate = lightUpdate; callback = () -> { // Set Modified nmsChunk.setLightCorrect(true); // Set Modified @@ -932,7 +940,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public void send() { synchronized (sendLock) { - PaperweightPlatformAdapter.sendChunk(this, serverLevel, chunkX, chunkZ); + PaperweightPlatformAdapter.sendChunk(new IntPair(chunkX, chunkZ), serverLevel, chunkX, chunkZ); } } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java index df71dae8c..838a5db53 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java @@ -7,9 +7,10 @@ import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.ReflectionUtils; import com.fastasyncworldedit.core.util.TaskManager; +import com.mojang.datafixers.util.Either; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; @@ -76,6 +77,7 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -241,15 +243,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } static boolean setSectionAtomic( + String worldName, + IntPair pair, LevelChunkSection[] sections, LevelChunkSection expected, LevelChunkSection value, int layer ) { - if (layer >= 0 && layer < sections.length) { - return ReflectionUtils.compareAndSet(sections, expected, value, layer); - } - return false; + return NMSAdapter.setSectionAtomic(worldName, pair, sections, expected, value, layer); } // There is no point in having a functional semaphore for paper servers. @@ -347,7 +348,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } @SuppressWarnings("deprecation") - public static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int chunkZ) { + public static void sendChunk(IntPair pair, ServerLevel nmsWorld, int chunkX, int chunkZ) { ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); if (chunkHolder == null) { return; @@ -360,32 +361,43 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { .getChunkSource() .getChunkAtIfLoadedImmediately(chunkX, chunkZ); } else { - levelChunk = chunkHolder.getTickingChunkFuture() - .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).orElse(null); + levelChunk = ((Optional) ((Either) chunkHolder + .getTickingChunkFuture() // method is not present with new paper chunk system + .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left()) + .orElse(null); } if (levelChunk == null) { return; } + StampLockHolder lockHolder = new StampLockHolder(); + NMSAdapter.beginChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder); + if (lockHolder.chunkLock == null) { + return; + } MinecraftServer.getServer().execute(() -> { - ClientboundLevelChunkWithLightPacket packet; - if (PaperLib.isPaper()) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - false // last false is to not bother with x-ray - ); - } else { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); + try { + ClientboundLevelChunkWithLightPacket packet; + if (PaperLib.isPaper()) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); + } else { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); + } + nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); + } finally { + NMSAdapter.endChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder); } - nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighter.java index ae09dcc58..c7b61575c 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighter.java @@ -2,6 +2,7 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4; import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.queue.IQueueExtent; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; @@ -67,7 +68,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); List beacons = null; @@ -509,6 +510,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc biomeData ); if (PaperweightPlatformAdapter.setSectionAtomic( + serverLevel.getWorld().getName(), + chunkPos, levelChunkSections, null, newSection, @@ -583,6 +586,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc biomeData ); if (PaperweightPlatformAdapter.setSectionAtomic( + serverLevel.getWorld().getName(), + chunkPos, levelChunkSections, null, newSection, @@ -644,7 +649,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc biomeRegistry, biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() ); - if (!PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, existingSection, + if (!PaperweightPlatformAdapter.setSectionAtomic( + serverLevel.getWorld().getName(), + chunkPos, + levelChunkSections, + existingSection, newSection, getSectionIndex )) { @@ -716,7 +725,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { for (UUID uuid : entityRemoves) { - Entity entity = nmsWorld.getEntities().get(uuid); + Entity entity = serverLevel.getEntities().get(uuid); if (entity != null) { removeEntity(entity); } @@ -755,7 +764,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc EntityType type = EntityType.byString(id).orElse(null); if (type != null) { - Entity entity = type.create(nmsWorld); + Entity entity = type.create(serverLevel); if (entity != null) { final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(linTag); for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { @@ -764,11 +773,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc entity.load(tag); entity.absMoveTo(x, y, z, yaw, pitch); entity.setUUID(NbtUtils.uuid(nativeTag)); - if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { + if (!serverLevel.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { LOGGER.warn( "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", id, - nmsWorld.getWorld().getName(), + serverLevel.getWorld().getName(), x, y, z @@ -798,11 +807,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc final int z = blockHash.z() + bz; final BlockPos pos = new BlockPos(x, y, z); - synchronized (nmsWorld) { - BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); + synchronized (serverLevel) { + BlockEntity tileEntity = serverLevel.getBlockEntity(pos); if (tileEntity == null || tileEntity.isRemoved()) { - nmsWorld.removeBlockEntity(pos); - tileEntity = nmsWorld.getBlockEntity(pos); + serverLevel.removeBlockEntity(pos); + tileEntity = serverLevel.getBlockEntity(pos); } if (tileEntity != null) { final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag()); @@ -821,7 +830,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc callback = null; } else { int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; - boolean finalLightUpdate = lightUpdate; callback = () -> { // Set Modified nmsChunk.setLightCorrect(true); // Set Modified @@ -927,7 +935,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public void send() { synchronized (sendLock) { - PaperweightPlatformAdapter.sendChunk(this, serverLevel, chunkX, chunkZ); + PaperweightPlatformAdapter.sendChunk(new IntPair(chunkX, chunkZ), serverLevel, chunkX, chunkZ); } } diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java index b4ed7c8ae..410152251 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java @@ -8,9 +8,10 @@ import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.ReflectionUtils; import com.fastasyncworldedit.core.util.TaskManager; +import com.mojang.datafixers.util.Either; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; @@ -31,7 +32,6 @@ import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.BitStorage; -import net.minecraft.util.ExceptionCollector; import net.minecraft.util.SimpleBitStorage; import net.minecraft.util.ThreadingDetector; import net.minecraft.util.Unit; @@ -76,6 +76,7 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -226,15 +227,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } static boolean setSectionAtomic( + String worldName, + IntPair pair, LevelChunkSection[] sections, LevelChunkSection expected, LevelChunkSection value, int layer ) { - if (layer >= 0 && layer < sections.length) { - return ReflectionUtils.compareAndSet(sections, expected, value, layer); - } - return false; + return NMSAdapter.setSectionAtomic(worldName, pair, sections, expected, value, layer); } // There is no point in having a functional semaphore for paper servers. @@ -332,7 +332,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } @SuppressWarnings("deprecation") - public static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int chunkZ) { + public static void sendChunk(IntPair pair, ServerLevel nmsWorld, int chunkX, int chunkZ) { ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); if (chunkHolder == null) { return; @@ -345,32 +345,43 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { .getChunkSource() .getChunkAtIfLoadedImmediately(chunkX, chunkZ); } else { - levelChunk = chunkHolder.getTickingChunkFuture() - .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).orElse(null); + levelChunk = ((Optional) ((Either) chunkHolder + .getTickingChunkFuture() // method is not present with new paper chunk system + .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left()) + .orElse(null); } if (levelChunk == null) { return; } + StampLockHolder lockHolder = new StampLockHolder(); + NMSAdapter.beginChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder); + if (lockHolder.chunkLock == null) { + return; + } MinecraftServer.getServer().execute(() -> { - ClientboundLevelChunkWithLightPacket packet; - if (PaperLib.isPaper()) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - false // last false is to not bother with x-ray - ); - } else { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); + try { + ClientboundLevelChunkWithLightPacket packet; + if (PaperLib.isPaper()) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); + } else { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); + } + nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); + } finally { + NMSAdapter.endChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder); } - nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); } diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightStarlightRelighter.java index f9d06922e..aa7b19b39 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightStarlightRelighter.java @@ -2,6 +2,7 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.queue.IQueueExtent; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; @@ -70,7 +71,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter CACHE = Collections.synchronizedMap(new WeakHashMap<>()); + + private final ConcurrentHashMap SENDING_CHUNKS = new ConcurrentHashMap<>(); + + /** + * Construct the object. + * + * @param world the world + */ + private FaweBukkitWorld(final World world) { + super(world); + } + + public static FaweBukkitWorld of(World world) { + return CACHE.compute(world, (__, val) -> { + if (val == null) { + return new FaweBukkitWorld(world); + } + val.updateReference(); + return val; + }); + } + + public static FaweBukkitWorld of(String worldName) { + World world = Bukkit.getWorld(worldName); + if (world == null) { + throw new UnsupportedOperationException("Unable to find org.bukkit.World instance for " + worldName + ". Is it loaded?"); + } + return of(world); + } + + public static ConcurrentHashMap getWorldSendingChunksMap(FaweBukkitWorld world) { + return world.SENDING_CHUNKS; + } + + public static ConcurrentHashMap getWorldSendingChunksMap(String worldName) { + return of(worldName).SENDING_CHUNKS; + } + + private void updateReference() { + World world = getWorld(); + World bukkitWorld = Bukkit.getWorld(worldNameRef); + if (bukkitWorld == null) { + throw new WorldUnloadedException(worldNameRef); + } else if (bukkitWorld != world) { + worldRef = new WeakReference<>(bukkitWorld); + } + } + +} diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSAdapter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSAdapter.java index 711c0fecc..4fc00996a 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSAdapter.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSAdapter.java @@ -1,12 +1,17 @@ package com.fastasyncworldedit.bukkit.adapter; +import com.fastasyncworldedit.bukkit.FaweBukkitWorld; import com.fastasyncworldedit.core.FAWEPlatformAdapterImpl; +import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.util.MathMan; +import com.fastasyncworldedit.core.util.ReflectionUtils; import com.sk89q.worldedit.world.block.BlockTypesCache; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.StampedLock; import java.util.function.Function; public class NMSAdapter implements FAWEPlatformAdapterImpl { @@ -140,4 +145,118 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl { ((BukkitGetBlocks) chunk).send(); } + /** + * Atomically set the given chunk section to the chunk section array stored in the chunk, given the expected existing chunk + * section instance at the given layer position. + *

    + * Acquires a (FAWE-implemented only) write-lock on the chunk packet lock, waiting if required before writing, then freeing + * the lock. Also sets a boolean to indicate a write is waiting and therefore reads should not occur. + *

    + * Utilises ConcurrentHashMap#compute for easy synchronisation for all of the above. Only tryWriteLock is used in blocks + * synchronised using ConcurrentHashMap methods. + * + * @since TODO + */ + protected static boolean setSectionAtomic( + String worldName, + IntPair pair, + LevelChunkSection[] sections, + LevelChunkSection expected, + LevelChunkSection value, + int layer + ) { + if (layer < 0 || layer >= sections.length) { + return false; + } + StampLockHolder holder = new StampLockHolder(); + ConcurrentHashMap chunks = FaweBukkitWorld.getWorldSendingChunksMap(worldName); + chunks.compute(pair, (k, lock) -> { + if (lock == null) { + lock = new ChunkSendLock(); + } else if (lock.writeWaiting) { + throw new IllegalStateException("Attempting to write chunk section when write is already ongoing?!"); + } + holder.stamp = lock.lock.tryWriteLock(); + holder.chunkLock = lock; + lock.writeWaiting = true; + return lock; + }); + try { + if (holder.stamp == 0) { + holder.stamp = holder.chunkLock.lock.writeLock(); + } + return ReflectionUtils.compareAndSet(sections, expected, value, layer); + } finally { + chunks = FaweBukkitWorld.getWorldSendingChunksMap(worldName); + chunks.computeIfPresent(pair, (k, lock) -> { + if (lock != holder.chunkLock) { + throw new IllegalStateException("SENDING_CHUNKS stored lock does not equal lock attempted to be unlocked?!"); + } + lock.lock.unlockWrite(holder.stamp); + lock.writeWaiting = false; + // Keep the lock, etc. in the map as we're going to be accessing again later when sending + return lock; + }); + } + } + + /** + * Called before sending a chunk packet, filling the given stamp and stampedLock arrays' zeroth indices if the chunk packet + * send should go ahead. + *

    + * Chunk packets should be sent if both of the following are met: + * - There is no more than one current packet send ongoing + * - There is no chunk section "write" waiting or ongoing, + * which are determined by the number of readers currently locking the StampedLock (i.e. the number of sends), if the + * stamped lock is currently write-locked and if the boolean for waiting write is true. + *

    + * Utilises ConcurrentHashMap#compute for easy synchronisation + * + * @since TODO + */ + protected static void beginChunkPacketSend(String worldName, IntPair pair, StampLockHolder stampedLock) { + ConcurrentHashMap chunks = FaweBukkitWorld.getWorldSendingChunksMap(worldName); + chunks.compute(pair, (k, lock) -> { + if (lock == null) { + lock = new ChunkSendLock(); + } + // Allow twice-read-locking, so if the packets have been created but not sent, we can queue another read + if (lock.writeWaiting || lock.lock.getReadLockCount() > 1 || lock.lock.isWriteLocked()) { + return lock; + } + stampedLock.stamp = lock.lock.readLock(); + stampedLock.chunkLock = lock; + return lock; + }); + } + + /** + * Releases the read lock acquired when sending a chunk packet for a chunk + * + * @since TODO + */ + protected static void endChunkPacketSend(String worldName, IntPair pair, StampLockHolder lockHolder) { + ConcurrentHashMap chunks = FaweBukkitWorld.getWorldSendingChunksMap(worldName); + chunks.computeIfPresent(pair, (k, lock) -> { + if (lock.lock != lockHolder.chunkLock.lock) { + throw new IllegalStateException("SENDING_CHUNKS stored lock does not equal lock attempted to be unlocked?!"); + } + lock.lock.unlockRead(lockHolder.stamp); + // Do not continue to store the lock if we may not need it (i.e. chunk has been sent, may not be sent again) + return null; + }); + } + + public static final class StampLockHolder { + public long stamp; + public ChunkSendLock chunkLock = null; + } + + public static final class ChunkSendLock { + + public final StampedLock lock = new StampedLock(); + public boolean writeWaiting = false; + + } + } 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 55912d770..9e4da5401 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 @@ -118,9 +118,9 @@ public class BukkitWorld extends AbstractWorld { HAS_MIN_Y = temp; } - private WeakReference worldRef; + protected WeakReference worldRef; //FAWE start - private final String worldNameRef; + protected final String worldNameRef; //FAWE end private final WorldNativeAccess worldNativeAccess; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/IntPair.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/IntPair.java index f7f451e79..b5667ccef 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/IntPair.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/IntPair.java @@ -4,7 +4,9 @@ public record IntPair(int x, int z) { @Override public int hashCode() { - return (x << 16) | (z & 0xFFFF); + int i = 1664525 * x + 1013904223; + int j = 1664525 * (z ^ -559038737) + 1013904223; + return i ^ j; } @Override From 3b6e5e83c98b019b1a7acf65df71921630935711 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sat, 28 Sep 2024 21:38:52 +0200 Subject: [PATCH 397/466] Fix NBT stripping and trimming (#2929) --- .../core/extent/LimitExtent.java | 4 +- .../core/extent/StripNBTExtent.java | 92 ++++++++++--------- .../core/queue/IBatchProcessor.java | 17 ++-- .../core/queue/IBlocks.java | 2 +- .../core/util/NbtUtils.java | 15 +++ 5 files changed, 74 insertions(+), 56 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java index d43078354..0bef1afc2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java @@ -512,8 +512,8 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess if (!processing) { return set; } - int tiles = set.getTiles().size(); - int ents = set.getEntities().size() + set.getEntityRemoves().size(); + int tiles = set.tiles().size(); + int ents = set.entities().size() + set.getEntityRemoves().size(); limit.THROW_MAX_CHANGES(tiles + ents); limit.THROW_MAX_BLOCKSTATES(tiles); limit.THROW_MAX_ENTITIES(ents); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java index c0b49c333..6939743d7 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java @@ -2,14 +2,12 @@ package com.fastasyncworldedit.core.extent; import com.fastasyncworldedit.core.extent.processor.ProcessorScope; import com.fastasyncworldedit.core.math.BlockVector3ChunkMap; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunk; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.util.ExtentTraverser; -import com.google.common.collect.ImmutableMap; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; @@ -20,16 +18,17 @@ import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.NbtValued; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinTag; import javax.annotation.Nullable; -import java.util.HashMap; +import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.UUID; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProcessor { @@ -75,79 +74,82 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc if (!(block instanceof BaseBlock localBlock)) { return block; } - if (!localBlock.hasNbtData()) { + final LinCompoundTag nbt = localBlock.getNbt(); + if (nbt == null) { return block; } - CompoundTag nbt = localBlock.getNbtData(); - Map> value = new HashMap<>(nbt.getValue()); + LinCompoundTag.Builder nbtBuilder = nbt.toBuilder(); for (String key : strip) { - value.remove(key); + nbtBuilder.remove(key); } - return (B) localBlock.toBaseBlock(new CompoundTag(value)); + return (B) localBlock.toBaseBlock(nbtBuilder.build()); } public T stripEntityNBT(T entity) { - if (!entity.hasNbtData()) { + LinCompoundTag nbt = entity.getNbt(); + if (nbt == null) { return entity; } - CompoundTag nbt = entity.getNbtData(); - Map> value = new HashMap<>(nbt.getValue()); + LinCompoundTag.Builder nbtBuilder = nbt.toBuilder(); for (String key : strip) { - value.remove(key); + nbtBuilder.remove(key); } - entity.setNbtData(new CompoundTag(value)); + entity.setNbt(nbtBuilder.build()); return entity; } @Override public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) { - Map tiles = set.getTiles(); - Set entities = set.getEntities(); + Map tiles = set.tiles(); + Collection entities = set.entities(); if (tiles.isEmpty() && entities.isEmpty()) { return set; } boolean isBv3ChunkMap = tiles instanceof BlockVector3ChunkMap; - for (final Map.Entry entry : tiles.entrySet()) { - ImmutableMap.Builder> map = ImmutableMap.builder(); - final AtomicBoolean isStripped = new AtomicBoolean(false); - entry.getValue().getValue().forEach((k, v) -> { - if (strip.contains(k.toLowerCase())) { - isStripped.set(true); - } else { - map.put(k, v); - } - }); - if (isStripped.get()) { + for (final var entry : tiles.entrySet()) { + FaweCompoundTag original = entry.getValue(); + FaweCompoundTag result = stripNbt(original); + if (original != result) { if (isBv3ChunkMap) { // Replace existing value with stripped value - tiles.put(entry.getKey(), new CompoundTag(map.build())); + tiles.put(entry.getKey(), result); } else { - entry.setValue(new CompoundTag(map.build())); + entry.setValue(result); } } } - Set stripped = new HashSet<>(); - Iterator iterator = entities.iterator(); + Set stripped = new HashSet<>(); + Iterator iterator = entities.iterator(); while (iterator.hasNext()) { - CompoundTag entity = iterator.next(); - ImmutableMap.Builder> map = ImmutableMap.builder(); - final AtomicBoolean isStripped = new AtomicBoolean(false); - entity.getValue().forEach((k, v) -> { - if (strip.contains(k.toUpperCase(Locale.ROOT))) { - isStripped.set(true); - } else { - map.put(k, v); - } - }); - if (isStripped.get()) { + FaweCompoundTag original = iterator.next(); + FaweCompoundTag result = stripNbt(original); + if (original != result) { iterator.remove(); - stripped.add(new CompoundTag(map.build())); + stripped.add(result); } } - set.getEntities().addAll(stripped); + // this relies on entities.addAll(...) not throwing an exception if empty+unmodifiable (=> stripped is empty too) + entities.addAll(stripped); return set; } + private FaweCompoundTag stripNbt( + FaweCompoundTag compoundTag + ) { + LinCompoundTag.Builder builder = LinCompoundTag.builder(); + boolean stripped = false; + for (var entry : compoundTag.linTag().value().entrySet()) { + String k = entry.getKey(); + LinTag v = entry.getValue(); + if (strip.contains(k.toLowerCase(Locale.ROOT))) { + stripped = true; + } else { + builder.put(k, v); + } + } + return stripped ? FaweCompoundTag.of(builder.build()) : compoundTag; + } + @Nullable @Override public Extent construct(final Extent child) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java index faec2f9f5..7bce208fc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java @@ -3,15 +3,16 @@ package com.fastasyncworldedit.core.queue; import com.fastasyncworldedit.core.extent.processor.EmptyBatchProcessor; import com.fastasyncworldedit.core.extent.processor.MultiBatchProcessor; import com.fastasyncworldedit.core.extent.processor.ProcessorScope; -import com.sk89q.jnbt.CompoundTag; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; +import com.fastasyncworldedit.core.util.NbtUtils; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockTypesCache; import javax.annotation.Nullable; +import java.util.Collection; import java.util.Map; -import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; import java.util.function.Function; @@ -156,11 +157,11 @@ public interface IBatchProcessor { */ @Deprecated(forRemoval = true, since = "2.8.4") default boolean trimNBT(IChunkSet set, Function contains) { - Set ents = set.getEntities(); + Collection ents = set.entities(); if (!ents.isEmpty()) { - ents.removeIf(ent -> !contains.apply(ent.getEntityPosition().toBlockPoint())); + ents.removeIf(ent -> !contains.apply(NbtUtils.entityPosition(ent).toBlockPoint())); } - Map tiles = set.getTiles(); + Map tiles = set.tiles(); if (!tiles.isEmpty()) { tiles.entrySet().removeIf(blockVector3CompoundTagEntry -> !contains .apply(blockVector3CompoundTagEntry.getKey())); @@ -177,11 +178,11 @@ public interface IBatchProcessor { default boolean trimNBT( IChunkSet set, Function containsEntity, Function containsTile ) { - Set ents = set.getEntities(); + Collection ents = set.entities(); if (!ents.isEmpty()) { - ents.removeIf(ent -> !containsEntity.apply(ent.getEntityPosition().toBlockPoint())); + ents.removeIf(ent -> !containsEntity.apply(NbtUtils.entityPosition(ent).toBlockPoint())); } - Map tiles = set.getTiles(); + Map tiles = set.tiles(); if (!tiles.isEmpty()) { tiles.entrySet().removeIf(blockVector3CompoundTagEntry -> !containsTile.apply(blockVector3CompoundTagEntry.getKey())); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java index bda12dbe3..3a9d71da1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java @@ -61,7 +61,7 @@ public interface IBlocks extends Trimable { @Deprecated(forRemoval = true, since = "2.11.2") default Map getTiles() { - return AdaptedMap.immutable(tiles(), pos -> pos, IBlocks::toCompoundTag); + return AdaptedMap.values(tiles(), ct -> FaweCompoundTag.of(ct.toLinTag()), IBlocks::toCompoundTag); } Map tiles(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java index ac606ab24..8b427c322 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java @@ -2,6 +2,7 @@ package com.fastasyncworldedit.core.util; import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.storage.InvalidFormatException; import org.enginehub.linbus.tree.LinByteTag; @@ -211,4 +212,18 @@ public final class NbtUtils { map.put("PersistentIDLSB", LinLongTag.of(uuid.getLeastSignificantBits())); } + /** + * {@return the position data of the given tag} + * + * @param compoundTag the tag to extract position information from + * @since TODO + */ + public static Vector3 entityPosition(FaweCompoundTag compoundTag) { + LinListTag pos = compoundTag.linTag().getListTag("Pos", LinTagType.doubleTag()); + double x = pos.get(0).valueAsDouble(); + double y = pos.get(1).valueAsDouble(); + double z = pos.get(2).valueAsDouble(); + return Vector3.at(x, y, z); + } + } From bf2874ef80676a71cf39dcfec5052b07f5d2c027 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sat, 28 Sep 2024 21:39:09 +0200 Subject: [PATCH 398/466] Implement vectorization of #existing and inverse masks (#2927) --- .../core/internal/simd/SimdSupport.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/SimdSupport.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/SimdSupport.java index 23d135fa6..5f2d6a711 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/SimdSupport.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/SimdSupport.java @@ -2,14 +2,17 @@ package com.fastasyncworldedit.core.internal.simd; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.filter.block.DelegateFilter; +import com.fastasyncworldedit.core.function.mask.InverseMask; import com.fastasyncworldedit.core.function.mask.SingleBlockStateMask; import com.fastasyncworldedit.core.queue.Filter; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.InverseSingleBlockStateMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypesCache; import jdk.incubator.vector.ShortVector; import jdk.incubator.vector.VectorOperators; @@ -44,10 +47,23 @@ public class SimdSupport { return switch (mask) { case SingleBlockStateMask single -> vectorizedTargetMask(single.getBlockState().getOrdinalChar()); case InverseSingleBlockStateMask inverse -> vectorizedTargetMaskInverse(inverse.getBlockState().getOrdinalChar()); + case ExistingBlockMask ignored -> vectorizedTargetMaskNonAir(); + case InverseMask inverse -> { + final VectorizedMask base = vectorizedTargetMask(inverse.inverse()); + if (base == null) { + yield null; + } + yield (set, get) -> base.compareVector(set, get).not(); + } default -> null; }; } + private static VectorizedMask vectorizedTargetMaskNonAir() { + // everything > VOID_AIR is not air + return (set, get) -> get.compare(VectorOperators.UNSIGNED_GT, BlockTypesCache.ReservedIDs.VOID_AIR); + } + private static VectorizedMask vectorizedTargetMask(char ordinal) { return (set, get) -> get.compare(VectorOperators.EQ, (short) ordinal); } From ba8b4e4ee8bea68720f8670812c25a9752399fb2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 28 Sep 2024 19:46:04 +0000 Subject: [PATCH 399/466] Update dependency com.sk89q.worldguard:worldguard-bukkit to v7.0.12 (#2917) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 64ae0731e..26aa321e5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,7 @@ snakeyaml = "2.0" # Plugins dummypermscompat = "1.10" -worldguard-bukkit = "7.0.10" +worldguard-bukkit = "7.0.12" mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" From be32b2264ac17599f0e2e00d31906244bbcc16be Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 29 Sep 2024 15:20:31 +0200 Subject: [PATCH 400/466] Bundle dependency updates Signed-off-by: Alexander Brandes --- buildSrc/build.gradle.kts | 2 +- buildSrc/src/main/kotlin/CommonJavaConfig.kt | 10 +++++----- gradle/libs.versions.toml | 6 +++--- .../adapters/adapter-1_21/build.gradle.kts | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 5735dc56c..2fb7aebc2 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -24,7 +24,7 @@ dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2") implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.2") - implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.2") + implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.3") constraints { val asmVersion = "[9.7,)" implementation("org.ow2.asm:asm:$asmVersion") { diff --git a/buildSrc/src/main/kotlin/CommonJavaConfig.kt b/buildSrc/src/main/kotlin/CommonJavaConfig.kt index ea921709c..0b90d1e06 100644 --- a/buildSrc/src/main/kotlin/CommonJavaConfig.kt +++ b/buildSrc/src/main/kotlin/CommonJavaConfig.kt @@ -41,11 +41,11 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean dependencies { "compileOnly"("com.google.code.findbugs:jsr305:3.0.2") - "testImplementation"("org.junit.jupiter:junit-jupiter-api:5.10.0") - "testImplementation"("org.junit.jupiter:junit-jupiter-params:5.10.0") - "testImplementation"("org.mockito:mockito-core:5.4.0") - "testImplementation"("org.mockito:mockito-junit-jupiter:5.4.0") - "testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:5.10.0") + "testImplementation"("org.junit.jupiter:junit-jupiter-api:5.11.1") + "testImplementation"("org.junit.jupiter:junit-jupiter-params:5.11.1") + "testImplementation"("org.mockito:mockito-core:5.14.0") + "testImplementation"("org.mockito:mockito-junit-jupiter:5.14.0") + "testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:5.11.1") } // Java 8 turns on doclint which we fail diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 26aa321e5..799844713 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,12 +18,12 @@ towny = "0.100.4.3" plotsquared = "7.3.11" # Third party -bstats = "3.0.3" +bstats = "3.1.0" sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.17.0" adventure-bukkit = "4.3.4" -checkerqual = "3.46.0" +checkerqual = "3.47.0" truezip = "6.8.4" auto-value = "1.11.0" findbugs = "3.0.2" @@ -47,7 +47,7 @@ text = "3.0.4" piston = "0.5.10" # Tests -mockito = "5.12.0" +mockito = "5.14.0" # Gradle plugins pluginyml = "0.6.0" diff --git a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts index fce133358..760b349d3 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.1-R0.1-20240922.215204-93") + the().paperDevBundle("1.21.1-R0.1-20240928.221611-107") compileOnly(libs.paperlib) } From d9171c18f2ab50fc68851eee8c70ccb2ab5414eb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 29 Sep 2024 13:32:58 +0000 Subject: [PATCH 401/466] Update dependency gradle to v8.10.2 (#2932) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.jar | Bin 43504 -> 43583 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 2c3521197d7c4586c843d1d3e9090525f1898cde..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 3990 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0aaefbcaf..df97d72b8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From cc2f6459f93bf04a76704d1ceccb4173d3b3b661 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 29 Sep 2024 13:34:55 +0000 Subject: [PATCH 402/466] Update dependency org.mockito:mockito-core to v5.14.0 (#2933) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-sponge/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-sponge/build.gradle.kts b/worldedit-sponge/build.gradle.kts index 1c3ad6b68..2c5c4d70b 100644 --- a/worldedit-sponge/build.gradle.kts +++ b/worldedit-sponge/build.gradle.kts @@ -28,7 +28,7 @@ dependencies { }) api("org.apache.logging.log4j:log4j-api") api("org.bstats:bstats-sponge:1.7") - testImplementation("org.mockito:mockito-core:5.12.0") + testImplementation("org.mockito:mockito-core:5.14.0") } <<<<<<< HEAD From 631269cafe7c1160bcfd5a431047e815349d6df1 Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 29 Sep 2024 18:27:53 +0100 Subject: [PATCH 403/466] fix: update to changes to spigot chunk future result (#2934) --- .../impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java | 9 ++------- .../impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java | 9 ++------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java index 838a5db53..e7672ce81 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java @@ -357,14 +357,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { LevelChunk levelChunk; if (PaperLib.isPaper()) { // getChunkAtIfLoadedImmediately is paper only - levelChunk = nmsWorld - .getChunkSource() - .getChunkAtIfLoadedImmediately(chunkX, chunkZ); + levelChunk = nmsWorld.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ); } else { - levelChunk = ((Optional) ((Either) chunkHolder - .getTickingChunkFuture() // method is not present with new paper chunk system - .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left()) - .orElse(null); + levelChunk = chunkHolder.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).orElse(null); } if (levelChunk == null) { return; diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java index 410152251..662140955 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java @@ -341,14 +341,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { LevelChunk levelChunk; if (PaperLib.isPaper()) { // getChunkAtIfLoadedImmediately is paper only - levelChunk = nmsWorld - .getChunkSource() - .getChunkAtIfLoadedImmediately(chunkX, chunkZ); + levelChunk = nmsWorld.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ); } else { - levelChunk = ((Optional) ((Either) chunkHolder - .getTickingChunkFuture() // method is not present with new paper chunk system - .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left()) - .orElse(null); + levelChunk = chunkHolder.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).orElse(null); } if (levelChunk == null) { return; From 7192e147d0e3e26dd77d8d5b185aeacc23823c10 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 01:32:16 +0000 Subject: [PATCH 404/466] Update dependency paperweight-userdev to v1.21.1-R0.1-20240929.223546-111 (#2935) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts index 760b349d3..feafadc70 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.1-R0.1-20240928.221611-107") + the().paperDevBundle("1.21.1-R0.1-20240929.223546-111") compileOnly(libs.paperlib) } From be3ae1afd9ffff08c82cd46a63fb34f228c18333 Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Mon, 7 Oct 2024 01:50:12 +0200 Subject: [PATCH 405/466] fix: don't require WEOrigin / WEOffset in MCEdit schematics (#2936) --- .../clipboard/io/MCEditSchematicReader.java | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java index 945cd6981..8e54249cd 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 @@ -57,6 +57,7 @@ import java.io.UncheckedIOException; import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.NoSuchElementException; import java.util.Set; /** @@ -126,18 +127,25 @@ public class MCEditSchematicReader extends NBTSchematicReader { short height = schematicTag.getTag("Height", LinTagType.shortTag()).valueAsShort(); short length = schematicTag.getTag("Length", LinTagType.shortTag()).valueAsShort(); - int originX = schematicTag.getTag("WEOriginX", LinTagType.intTag()).valueAsInt(); - int originY = schematicTag.getTag("WEOriginY", LinTagType.intTag()).valueAsInt(); - int originZ = schematicTag.getTag("WEOriginZ", LinTagType.intTag()).valueAsInt(); - BlockVector3 min = BlockVector3.at(originX, originY, originZ); + try { + int originX = schematicTag.getTag("WEOriginX", LinTagType.intTag()).valueAsInt(); + int originY = schematicTag.getTag("WEOriginY", LinTagType.intTag()).valueAsInt(); + int originZ = schematicTag.getTag("WEOriginZ", LinTagType.intTag()).valueAsInt(); + BlockVector3 min = BlockVector3.at(originX, originY, originZ); + + int offsetX = schematicTag.getTag("WEOffsetX", LinTagType.intTag()).valueAsInt(); + int offsetY = schematicTag.getTag("WEOffsetY", LinTagType.intTag()).valueAsInt(); + int offsetZ = schematicTag.getTag("WEOffsetZ", LinTagType.intTag()).valueAsInt(); + BlockVector3 offset = BlockVector3.at(offsetX, offsetY, offsetZ); + + origin = min.subtract(offset); + region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE)); + } catch (NoSuchElementException e) { + origin = BlockVector3.ZERO; + region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE)); + } - int offsetX = schematicTag.getTag("WEOffsetX", LinTagType.intTag()).valueAsInt(); - int offsetY = schematicTag.getTag("WEOffsetY", LinTagType.intTag()).valueAsInt(); - int offsetZ = schematicTag.getTag("WEOffsetZ", LinTagType.intTag()).valueAsInt(); - BlockVector3 offset = BlockVector3.at(offsetX, offsetY, offsetZ); - origin = min.subtract(offset); - region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE)); // ==================================================================== // Blocks From d58026dd045d305a76b2ddfe1357a8fc30a736da Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 01:06:05 +0000 Subject: [PATCH 406/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.4.4 (#2940) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 799844713..c27590f1a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.4.3" +towny = "0.100.4.4" plotsquared = "7.3.11" # Third party From 8c9074ff73d8bdfe7dc3438d17eaa2e723124555 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 03:41:59 +0000 Subject: [PATCH 407/466] Update dependency org.mockito:mockito-core to v5.14.1 (#2941) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- worldedit-sponge/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c27590f1a..a11448070 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -47,7 +47,7 @@ text = "3.0.4" piston = "0.5.10" # Tests -mockito = "5.14.0" +mockito = "5.14.1" # Gradle plugins pluginyml = "0.6.0" diff --git a/worldedit-sponge/build.gradle.kts b/worldedit-sponge/build.gradle.kts index 2c5c4d70b..fedd48c00 100644 --- a/worldedit-sponge/build.gradle.kts +++ b/worldedit-sponge/build.gradle.kts @@ -28,7 +28,7 @@ dependencies { }) api("org.apache.logging.log4j:log4j-api") api("org.bstats:bstats-sponge:1.7") - testImplementation("org.mockito:mockito-core:5.14.0") + testImplementation("org.mockito:mockito-core:5.14.1") } <<<<<<< HEAD From b343be40c8750572ed437cafdf46cc8839628167 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 03:42:32 +0000 Subject: [PATCH 408/466] Update dependency paperweight-userdev to v1.21.1-R0.1-20241003.152200-116 (#2942) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts index feafadc70..32e298776 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.1-R0.1-20240929.223546-111") + the().paperDevBundle("1.21.1-R0.1-20241003.152200-116") compileOnly(libs.paperlib) } From bdadef6511945b366d360b2c70af75050e19df30 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 13 Oct 2024 08:39:24 +0000 Subject: [PATCH 409/466] Update dependency com.gradleup.shadow:shadow-gradle-plugin to v8.3.3 (#2939) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 2fb7aebc2..f2d748d25 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -23,7 +23,7 @@ val properties = Properties().also { props -> dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2") - implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.2") + implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.3") implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.3") constraints { val asmVersion = "[9.7,)" From ced53d3ce8e8c1cd49d441a3094a8126f8b5e464 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 00:44:46 +0000 Subject: [PATCH 410/466] Update dependency org.ajoberstar.grgit:grgit-gradle to v5.3.0 (#2947) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index f2d748d25..ae6cc0d17 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -22,7 +22,7 @@ val properties = Properties().also { props -> dependencies { implementation(gradleApi()) - implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2") + implementation("org.ajoberstar.grgit:grgit-gradle:5.3.0") implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.3") implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.3") constraints { From 91bdd15c18218240c07a33a2c6dcc041a82c2947 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 00:46:11 +0000 Subject: [PATCH 411/466] Update dependency paperweight-userdev to v1.21.1-R0.1-20241012.212042-119 (#2946) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts index 32e298776..4face9389 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.1-R0.1-20241003.152200-116") + the().paperDevBundle("1.21.1-R0.1-20241012.212042-119") compileOnly(libs.paperlib) } From 9a40bab09addafc9cb04367575efb1ce32608529 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 01:04:46 +0000 Subject: [PATCH 412/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.4.5 (#2952) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a11448070..72ffea124 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.4.4" +towny = "0.100.4.5" plotsquared = "7.3.11" # Third party From a58910d17ba2884ac4910736853c3d33e78d71aa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 01:05:04 +0000 Subject: [PATCH 413/466] Update dependency org.mockito:mockito-core to v5.14.2 (#2953) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- worldedit-sponge/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 72ffea124..cb69e553b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -47,7 +47,7 @@ text = "3.0.4" piston = "0.5.10" # Tests -mockito = "5.14.1" +mockito = "5.14.2" # Gradle plugins pluginyml = "0.6.0" diff --git a/worldedit-sponge/build.gradle.kts b/worldedit-sponge/build.gradle.kts index fedd48c00..356a4d635 100644 --- a/worldedit-sponge/build.gradle.kts +++ b/worldedit-sponge/build.gradle.kts @@ -28,7 +28,7 @@ dependencies { }) api("org.apache.logging.log4j:log4j-api") api("org.bstats:bstats-sponge:1.7") - testImplementation("org.mockito:mockito-core:5.14.1") + testImplementation("org.mockito:mockito-core:5.14.2") } <<<<<<< HEAD From 3806a82f6f310609ef5cc3f6c77192dc1810f1dc Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Mon, 21 Oct 2024 18:16:41 +0200 Subject: [PATCH 414/466] Use data version provided by MC (#2955) --- .../adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java index b958c8ba7..125d000bf 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java @@ -65,6 +65,7 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.item.ItemType; +import net.minecraft.SharedConstants; import net.minecraft.Util; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; @@ -124,7 +125,6 @@ import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.craftbukkit.inventory.CraftItemStack; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.generator.ChunkGenerator; @@ -194,7 +194,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter Date: Thu, 24 Oct 2024 20:25:49 +0200 Subject: [PATCH 415/466] Fix ChunkHolder tile set delegation (#2949) --- .../core/queue/implementation/chunk/ChunkHolder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java index 7c36eb94c..5e951cd2b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java @@ -924,7 +924,7 @@ public class ChunkHolder> implements IQueueChunk { @Override public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tag) { - return false; + return delegate.set(this).tile(x, y, z, tag); } /** From 65de3642d644f57a2d4552561c1336b4e6904bff Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Thu, 24 Oct 2024 20:26:05 +0200 Subject: [PATCH 416/466] Use default nbt when parsing blocks (#2945) --- .../worldedit/extension/factory/parser/DefaultBlockParser.java | 1 + 1 file changed, 1 insertion(+) 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 03cfb51e3..7ef47de45 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 @@ -465,6 +465,7 @@ public class DefaultBlockParser extends InputParser { if (state == null) { throw new NoMatchException(Caption.of("fawe.error.invalid-block-type", TextComponent.of(input))); } + nbt = state.getNbtData(); } //FAWE end From 7d6643b45237126b1536282e9943bcc0f9ae303f Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Fri, 25 Oct 2024 19:59:53 +0200 Subject: [PATCH 417/466] Fix vectorized CountFilter (#2943) --- .../core/extent/filter/CountFilter.java | 5 +++-- .../core/extent/filter/LinkedFilter.java | 7 ++++--- .../core/extent/filter/MaskFilter.java | 5 ++--- .../core/internal/simd/SimdSupport.java | 6 ++++-- .../internal/simd/VectorizedCharFilterBlock.java | 5 ++++- .../core/internal/simd/VectorizedFilter.java | 13 ++++++++++++- .../core/internal/simd/VectorizedMask.java | 15 ++++++++++++++- 7 files changed, 43 insertions(+), 13 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/CountFilter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/CountFilter.java index f6844e684..7c6767bf2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/CountFilter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/CountFilter.java @@ -3,6 +3,7 @@ package com.fastasyncworldedit.core.extent.filter; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; import com.fastasyncworldedit.core.internal.simd.VectorizedFilter; import jdk.incubator.vector.ShortVector; +import jdk.incubator.vector.VectorMask; public class CountFilter extends ForkedFilter implements VectorizedFilter { @@ -36,8 +37,8 @@ public class CountFilter extends ForkedFilter implements Vectorized } @Override - public ShortVector applyVector(final ShortVector get, final ShortVector set) { - total += set.length(); + public ShortVector applyVector(final ShortVector get, final ShortVector set, VectorMask mask) { + total += mask.trueCount(); return set; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/LinkedFilter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/LinkedFilter.java index 26700ccc5..ff57a4625 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/LinkedFilter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/LinkedFilter.java @@ -6,6 +6,7 @@ import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.IChunk; import com.sk89q.worldedit.regions.Region; import jdk.incubator.vector.ShortVector; +import jdk.incubator.vector.VectorMask; import org.jetbrains.annotations.Nullable; /** @@ -77,9 +78,9 @@ public sealed class LinkedFilter implements } @Override - public ShortVector applyVector(final ShortVector get, final ShortVector set) { - ShortVector res = getLeft().applyVector(get, set); - return getRight().applyVector(get, res); + public ShortVector applyVector(final ShortVector get, final ShortVector set, VectorMask mask) { + ShortVector res = getLeft().applyVector(get, set, mask); + return getRight().applyVector(get, res, mask); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/MaskFilter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/MaskFilter.java index ac31938e2..2ce1527df 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/MaskFilter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/MaskFilter.java @@ -82,11 +82,10 @@ public class MaskFilter extends DelegateFilter { } @Override - public ShortVector applyVector(final ShortVector get, final ShortVector set) { + public ShortVector applyVector(final ShortVector get, final ShortVector set, VectorMask mask) { final T parent = getParent(); VectorMask masked = vectorizedMask.compareVector(set, get); - ShortVector res = parent.applyVector(get, set); - res = set.blend(res, masked); + ShortVector res = parent.applyVector(get, set, mask.and(masked)); VectorMask changed = res.compare(VectorOperators.NE, set); changes.getAndAdd(changed.trueCount()); return res; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/SimdSupport.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/SimdSupport.java index 5f2d6a711..eefdc1929 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/SimdSupport.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/SimdSupport.java @@ -14,6 +14,7 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypesCache; import jdk.incubator.vector.ShortVector; +import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import javax.annotation.Nullable; @@ -101,8 +102,9 @@ public class SimdSupport { } @Override - public ShortVector applyVector(final ShortVector get, final ShortVector set) { - return ShortVector.broadcast(ShortVector.SPECIES_PREFERRED, ordinal); + public ShortVector applyVector(final ShortVector get, final ShortVector set, VectorMask mask) { + // only change the lanes the mask dictates us to change, keep the rest + return set.blend(ShortVector.broadcast(ShortVector.SPECIES_PREFERRED, ordinal), mask); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedCharFilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedCharFilterBlock.java index 5c15da22a..9f557b134 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedCharFilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedCharFilterBlock.java @@ -4,6 +4,7 @@ import com.fastasyncworldedit.core.extent.filter.block.CharFilterBlock; import com.fastasyncworldedit.core.queue.Filter; import com.sk89q.worldedit.extent.Extent; import jdk.incubator.vector.ShortVector; +import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorSpecies; public class VectorizedCharFilterBlock extends CharFilterBlock { @@ -18,15 +19,17 @@ public class VectorizedCharFilterBlock extends CharFilterBlock { throw new IllegalStateException("Unexpected VectorizedCharFilterBlock " + filter); } final VectorSpecies species = ShortVector.SPECIES_PREFERRED; + // TODO can we avoid eager initSet? initSet(); // set array is null before char[] setArr = this.setArr; assert setArr != null; char[] getArr = this.getArr; // assume setArr.length == getArr.length == 4096 + VectorMask affectAll = species.maskAll(true); for (int i = 0; i < 4096; i += species.length()) { ShortVector set = ShortVector.fromCharArray(species, setArr, i); ShortVector get = ShortVector.fromCharArray(species, getArr, i); - ShortVector res = vecFilter.applyVector(get, set); + ShortVector res = vecFilter.applyVector(get, set, affectAll); res.intoCharArray(setArr, i); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedFilter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedFilter.java index 7357bbd59..b0801fcd0 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedFilter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedFilter.java @@ -2,7 +2,18 @@ package com.fastasyncworldedit.core.internal.simd; import com.fastasyncworldedit.core.queue.Filter; import jdk.incubator.vector.ShortVector; +import jdk.incubator.vector.VectorMask; public interface VectorizedFilter extends Filter { - ShortVector applyVector(ShortVector get, ShortVector set); + + /** + * Applies a filter to a vector pair of get and set. + * + * @param get the get vector + * @param set the set vector + * @param mask the mask with the lanes set to true which should be affected by the filter + * @return the resulting set vector. + */ + ShortVector applyVector(ShortVector get, ShortVector set, VectorMask mask); + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedMask.java index 0f453f32b..a6fd18b48 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedMask.java @@ -3,6 +3,7 @@ package com.fastasyncworldedit.core.internal.simd; import com.fastasyncworldedit.core.queue.IChunk; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; +import com.sk89q.worldedit.world.block.BlockTypesCache; import jdk.incubator.vector.ShortVector; import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorSpecies; @@ -31,10 +32,22 @@ public interface VectorizedMask { } } + /** + * {@return the set vector with all lanes that do not match this mask set to 0} + * + * @param set the set vector + * @param get the get vector + */ default ShortVector processVector(ShortVector set, ShortVector get) { - return set.blend(0, compareVector(set, get).not()); + return set.blend(BlockTypesCache.ReservedIDs.__RESERVED__, compareVector(set, get).not()); } + /** + * {@return a mask with all lanes set that match this mask} + * + * @param set the set vector + * @param get the get vector + */ VectorMask compareVector(ShortVector set, ShortVector get); } From 8582e587f104d69e9eb7bab817a5a7cb89ad4275 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 18:07:01 +0000 Subject: [PATCH 418/466] Update dependency org.checkerframework:checker-qual to v3.48.1 (#2958) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cb69e553b..bb6467efd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.17.0" adventure-bukkit = "4.3.4" -checkerqual = "3.47.0" +checkerqual = "3.48.1" truezip = "6.8.4" auto-value = "1.11.0" findbugs = "3.0.2" From af4d0da9949af18c6d1a0ae061a8c2e1dcd89ad3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 18:07:06 +0000 Subject: [PATCH 419/466] Update dependency org.enginehub.lin-bus:lin-bus-bom to v0.2.0 (#2959) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bb6467efd..00fcb98ad 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -40,7 +40,7 @@ paperlib = "1.0.8" paster = "1.1.6" vault = "1.7.1" serverlib = "2.3.6" -linbus = "0.1.2" +linbus = "0.2.0" ## Internal text-adapter = "3.0.6" text = "3.0.4" From aca9857085b49bc10d3e10dbf45ae56aa4a64376 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 18:15:18 +0000 Subject: [PATCH 420/466] Update dependency me.lucko:fabric-permissions-api to v0.3.2 (#2960) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-fabric/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-fabric/build.gradle.kts b/worldedit-fabric/build.gradle.kts index 4ba08c6eb..9f785fd6d 100644 --- a/worldedit-fabric/build.gradle.kts +++ b/worldedit-fabric/build.gradle.kts @@ -100,7 +100,7 @@ dependencies { } // No need for this at runtime - "modCompileOnly"("me.lucko:fabric-permissions-api:0.3.1") + "modCompileOnly"("me.lucko:fabric-permissions-api:0.3.2") // Hook these up manually, because Fabric doesn't seem to quite do it properly. "compileOnly"("net.fabricmc:sponge-mixin:${project.versions.mixin}") From 5121bb8b992334ac7cd18bfa1bc9848430ff0378 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 18:15:35 +0000 Subject: [PATCH 421/466] Update dependency paperweight-userdev to v1.21.1-R0.1-20241021.162528-124 (#2957) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts index 4face9389..a2b3da35a 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.1-R0.1-20241012.212042-119") + the().paperDevBundle("1.21.1-R0.1-20241021.162528-124") compileOnly(libs.paperlib) } From f0af979f5fb4a48536baecfaba641e1ccd798471 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Fri, 25 Oct 2024 20:33:44 +0200 Subject: [PATCH 422/466] Release 2.12.0 Signed-off-by: Alexander Brandes --- build.gradle.kts | 4 ++-- .../com/fastasyncworldedit/bukkit/adapter/NMSAdapter.java | 6 +++--- .../com/fastasyncworldedit/core/extent/LimitExtent.java | 6 +++--- .../core/extent/clipboard/LinearClipboard.java | 2 +- .../java/com/fastasyncworldedit/core/limit/FaweLimit.java | 2 +- .../java/com/fastasyncworldedit/core/util/NbtUtils.java | 2 +- .../java/com/sk89q/worldedit/command/tool/brush/Brush.java | 2 +- .../command/util/annotation/SynchronousSettingExpected.java | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index adab2bddb..0545bf5fa 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.11.3") +var rootVersion by extra("2.12.0") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s-%s", rootVersion, buildNumber) +version = String.format("%s", rootVersion) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSAdapter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSAdapter.java index 4fc00996a..f8b240bb9 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSAdapter.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSAdapter.java @@ -155,7 +155,7 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl { * Utilises ConcurrentHashMap#compute for easy synchronisation for all of the above. Only tryWriteLock is used in blocks * synchronised using ConcurrentHashMap methods. * - * @since TODO + * @since 2.12.0 */ protected static boolean setSectionAtomic( String worldName, @@ -212,7 +212,7 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl { *

    * Utilises ConcurrentHashMap#compute for easy synchronisation * - * @since TODO + * @since 2.12.0 */ protected static void beginChunkPacketSend(String worldName, IntPair pair, StampLockHolder stampedLock) { ConcurrentHashMap chunks = FaweBukkitWorld.getWorldSendingChunksMap(worldName); @@ -233,7 +233,7 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl { /** * Releases the read lock acquired when sending a chunk packet for a chunk * - * @since TODO + * @since 2.12.0 */ protected static void endChunkPacketSend(String worldName, IntPair pair, StampLockHolder lockHolder) { ConcurrentHashMap chunks = FaweBukkitWorld.getWorldSendingChunksMap(worldName); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java index 0bef1afc2..90ca09810 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java @@ -55,7 +55,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess * @param limit the limit * @deprecated Use {@link LimitExtent#LimitExtent(Extent, FaweLimit, Consumer, boolean)} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.12.0") public LimitExtent(Extent extent, FaweLimit limit) { this(extent, limit, c -> { }); @@ -69,7 +69,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess * @param onErrorMessage consumer to handle a component generated by exceptions * @deprecated Use {@link LimitExtent#LimitExtent(Extent, FaweLimit, Consumer, boolean)} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.12.0") public LimitExtent(Extent extent, FaweLimit limit, Consumer onErrorMessage) { this(extent, limit, onErrorMessage, false); } @@ -81,7 +81,7 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess * @param limit the limit * @param onErrorMessage consumer to handle a component generated by exceptions * @param processing if this limit extent is expected to be processing - * @since TODO + * @since 2.12.0 */ public LimitExtent( Extent extent, diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java index cc0bb07f6..7d60f3ee4 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java @@ -60,7 +60,7 @@ public abstract class LinearClipboard extends SimpleClipboard { /** * @deprecated will be removed as it is unused and uses outdated types */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.12.0") public abstract Collection getTileEntities(); @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java index 2bb002914..0dde6baac 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java @@ -299,7 +299,7 @@ public class FaweLimit { /** * Get an {@link FaweLimit} representing the amount of a limit used from a given "original" limit * - * @since TODO + * @since 2.12.0 */ public FaweLimit getLimitUsed(FaweLimit originalLimit) { FaweLimit newLimit = new FaweLimit(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java index 8b427c322..07a047360 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java @@ -216,7 +216,7 @@ public final class NbtUtils { * {@return the position data of the given tag} * * @param compoundTag the tag to extract position information from - * @since TODO + * @since 2.12.0 */ public static Vector3 entityPosition(FaweCompoundTag compoundTag) { LinListTag pos = compoundTag.linTag().getListTag("Pos", LinTagType.doubleTag()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java index e38ae0d99..938a2f8dd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/Brush.java @@ -44,7 +44,7 @@ public interface Brush { /** * If this brush is expected to set blocks synchronously, i.e. from one thread (at a time) * - * @since TODO + * @since 2.12.0 */ default boolean setsSynchronously() { return true; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/SynchronousSettingExpected.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/SynchronousSettingExpected.java index 3cc936fda..6d94fb3ff 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/SynchronousSettingExpected.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/SynchronousSettingExpected.java @@ -10,7 +10,7 @@ import java.lang.annotation.Target; /** * Indicates it is expected that blocks will only be set synchronously, i.e. from one thread (at a time) * - * @since TODO + * @since 2.12.0 */ @Retention(RetentionPolicy.RUNTIME) @Target({ From c252850400a71513b79f1a2ef4b2a1b7cda4c499 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Fri, 25 Oct 2024 20:44:56 +0200 Subject: [PATCH 423/466] Back to snapshot for development Signed-off-by: Alexander Brandes --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 0545bf5fa..824a50ad1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.12.0") +var rootVersion by extra("2.12.1") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s", rootVersion) +version = String.format("%s-%s", rootVersion, buildNumber) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From b958d2db44c52ca479fb1fc48ede4a75760ce16b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 01:40:41 +0000 Subject: [PATCH 424/466] Update dependency io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin to v1.7.4 (#2965) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index ae6cc0d17..4405e004e 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -24,7 +24,7 @@ dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.3.0") implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.3") - implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.3") + implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.4") constraints { val asmVersion = "[9.7,)" implementation("org.ow2.asm:asm:$asmVersion") { From 42b977b9eb5c51654e2cd09514e797458c7903c8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 01:41:01 +0000 Subject: [PATCH 425/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.4.7 (#2964) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 00fcb98ad..96ca9a71d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.4.5" +towny = "0.100.4.7" plotsquared = "7.3.11" # Third party From d959778dfc6b066810dc6d282bcf5b0ccdef3d4b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 03:20:42 +0000 Subject: [PATCH 426/466] Update plotsquared to v7.3.12 (#2966) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 96ca9a71d..e1f5f0dd8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" towny = "0.100.4.7" -plotsquared = "7.3.11" +plotsquared = "7.3.12" # Third party bstats = "3.1.0" From d56c6ea10303f7ef989410db5759759316c8f8c9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 01:31:16 +0000 Subject: [PATCH 427/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.4.9 (#2978) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e1f5f0dd8..b4149053b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.4.7" +towny = "0.100.4.9" plotsquared = "7.3.12" # Third party From 8b11ad0c0adf98132ba01c8d9dcd0f2e1cdb1460 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 01:31:28 +0000 Subject: [PATCH 428/466] Update dependency com.gradleup.shadow:shadow-gradle-plugin to v8.3.5 (#2977) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 4405e004e..670f38b88 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -23,7 +23,7 @@ val properties = Properties().also { props -> dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.3.0") - implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.3") + implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.5") implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.4") constraints { val asmVersion = "[9.7,)" From fdf8ac67afd4c7ae54e577227d2a094d5484734b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 03:26:48 +0000 Subject: [PATCH 429/466] Update dependency org.checkerframework:checker-qual to v3.48.2 (#2980) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b4149053b..2730e6df3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.17.0" adventure-bukkit = "4.3.4" -checkerqual = "3.48.1" +checkerqual = "3.48.2" truezip = "6.8.4" auto-value = "1.11.0" findbugs = "3.0.2" From c213dae5479ad24714b185de131570e78933e813 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 03:27:14 +0000 Subject: [PATCH 430/466] Update dependency me.lucko:fabric-permissions-api to v0.3.3 (#2979) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-fabric/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-fabric/build.gradle.kts b/worldedit-fabric/build.gradle.kts index 9f785fd6d..9bd557d7d 100644 --- a/worldedit-fabric/build.gradle.kts +++ b/worldedit-fabric/build.gradle.kts @@ -100,7 +100,7 @@ dependencies { } // No need for this at runtime - "modCompileOnly"("me.lucko:fabric-permissions-api:0.3.2") + "modCompileOnly"("me.lucko:fabric-permissions-api:0.3.3") // Hook these up manually, because Fabric doesn't seem to quite do it properly. "compileOnly"("net.fabricmc:sponge-mixin:${project.versions.mixin}") From 44f7b63fb120b7ce79975e45e966278ccfe1ba33 Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 4 Nov 2024 11:20:17 +0000 Subject: [PATCH 431/466] Allow stacking by block units with //stack (#1539) (#2973) - closes #2968 Co-authored-by: Matthew Miller --- .../java/com/sk89q/worldedit/EditSession.java | 48 +++++++++++++++++-- .../worldedit/command/RegionCommands.java | 19 +++++--- .../src/main/resources/lang/strings.json | 1 + 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 85fbde830..95bffb681 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -127,6 +127,7 @@ import com.sk89q.worldedit.regions.FlatRegion; import com.sk89q.worldedit.regions.NullRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionIntersection; +import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.regions.Regions; import com.sk89q.worldedit.regions.shape.ArbitraryBiomeShape; import com.sk89q.worldedit.regions.shape.ArbitraryShape; @@ -1804,18 +1805,59 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public int stackCuboidRegion( - Region region, BlockVector3 offset, int count, - boolean copyEntities, boolean copyBiomes, Mask mask + Region region, + BlockVector3 offset, + int count, + boolean copyEntities, + boolean copyBiomes, + Mask mask ) throws MaxChangedBlocksException { checkNotNull(region); checkNotNull(offset); + + BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1); + try { + return stackRegionBlockUnits(region, offset.multiply(size), count, copyEntities, copyBiomes, mask); + } catch (RegionOperationException e) { + // Should never be able to happen + throw new AssertionError(e); + } + } + + /** + * Stack a region using block units. + * + * @param region the region to stack + * @param offset how far to move the contents each stack in block units + * @param count the number of times to stack + * @param copyEntities true to copy entities + * @param copyBiomes true to copy biomes + * @param mask source mask for the operation (only matching blocks are copied) + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + * @throws RegionOperationException thrown if the region operation is invalid + */ + public int stackRegionBlockUnits( + Region region, + BlockVector3 offset, + int count, + boolean copyEntities, + boolean copyBiomes, + Mask mask + ) throws MaxChangedBlocksException, RegionOperationException { + checkNotNull(region); + checkNotNull(offset); checkArgument(count >= 1, "count >= 1 required"); BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1); + BlockVector3 offsetAbs = offset.abs(); + if (offsetAbs.x() < size.x() && offsetAbs.y() < size.y() && offsetAbs.z() < size.z()) { + throw new RegionOperationException(Caption.of("worldedit.stack.intersecting-region")); + } BlockVector3 to = region.getMinimumPoint(); ForwardExtentCopy copy = new ForwardExtentCopy(this, region, this, to); copy.setRepetitions(count); - copy.setTransform(new AffineTransform().translate(offset.multiply(size))); + copy.setTransform(new AffineTransform().translate(offset)); copy.setCopyingEntities(copyEntities); copy.setCopyingBiomes(copyBiomes); final Region allowedRegion; 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 565aecb9a..2847542a5 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 @@ -594,7 +594,7 @@ public class RegionCommands { session.getRegionSelector(world).learnChanges(); session.getRegionSelector(world).explainRegionAdjust(actor, session); } catch (RegionOperationException e) { - actor.printError(TextComponent.of(e.getMessage())); + actor.printError(e.getRichMessage()); } } @@ -640,7 +640,7 @@ public class RegionCommands { int count, @Arg(desc = "How far to move the contents each stack", def = Offset.FORWARD) @Offset - BlockVector3 direction, + BlockVector3 offset, @Switch(name = 's', desc = "Shift the selection to the last stacked copy") boolean moveSelection, @Switch(name = 'a', desc = "Ignore air blocks") @@ -649,6 +649,8 @@ public class RegionCommands { boolean copyEntities, @Switch(name = 'b', desc = "Also copy biomes") boolean copyBiomes, + @Switch(name = 'r', desc = "Use block units") + boolean blockUnits, @ArgFlag(name = 'm', desc = "Set the include mask, non-matching blocks become air") Mask mask ) throws WorldEditException { @@ -668,19 +670,24 @@ public class RegionCommands { combinedMask = mask; } - int affected = editSession.stackCuboidRegion(region, direction, count, copyEntities, copyBiomes, combinedMask); + int affected; + if (blockUnits) { + affected = editSession.stackRegionBlockUnits(region, offset, count, copyEntities, copyBiomes, combinedMask); + } else { + affected = editSession.stackCuboidRegion(region, offset, count, copyEntities, copyBiomes, combinedMask); + } if (moveSelection) { try { final BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1); - - final BlockVector3 shiftVector = direction.multiply(size).multiply(count); + final BlockVector3 shiftSize = blockUnits ? offset : offset.multiply(size); + final BlockVector3 shiftVector = shiftSize.multiply(count); region.shift(shiftVector); session.getRegionSelector(world).learnChanges(); session.getRegionSelector(world).explainRegionAdjust(actor, session); } catch (RegionOperationException e) { - actor.printError(TextComponent.of(e.getMessage())); + actor.printError(e.getRichMessage()); } } diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index fea3e7dd5..0b7a63b8d 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -478,6 +478,7 @@ "worldedit.curve.convex-only": "//curve only works with convex polyhedral selections", "worldedit.replace.replaced": "{0} blocks have been replaced.", "worldedit.stack.changed": "{0} blocks changed. Undo with //undo", + "worldedit.stack.intersecting-region": "Stack offset must not collide with the region when using block units", "worldedit.regen.regenerated": "Region regenerated.", "worldedit.regen.failed": "Unable to regenerate chunks. Check console for details.", "worldedit.walls.changed": "{0} blocks have been changed.", From 9eafbf1c26dd49b41801c2a9d2efd09d898f5e82 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Mon, 4 Nov 2024 12:20:51 +0100 Subject: [PATCH 432/466] Fix direction changes for //undo (#2972) --- .../core/history/changeset/FaweStreamChangeSet.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java index e50030d21..f8ff1956f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java @@ -817,6 +817,7 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { @Override protected void write(final MutableTileChange change, final CompoundTag tag) { change.tag = tag; + change.create = create; } @Override @@ -845,6 +846,7 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { @Override protected void write(final MutableEntityChange change, final CompoundTag tag) { change.tag = tag; + change.create = create; } @Override From bd94632c479d1c981a833972fd6eb84b8c9d40cf Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Mon, 4 Nov 2024 12:21:14 +0100 Subject: [PATCH 433/466] Deduplicate adapter fields into superclass (#2967) Move common adapter fields into supertype --- .../impl/fawe/v1_20_R2/PaperweightFaweAdapter.java | 10 +--------- .../impl/fawe/v1_20_R3/PaperweightFaweAdapter.java | 10 +--------- .../impl/fawe/v1_20_R4/PaperweightFaweAdapter.java | 10 +--------- .../impl/fawe/v1_21_R1/PaperweightFaweAdapter.java | 10 +--------- .../bukkit/adapter/FaweAdapter.java | 13 +++++++++++++ 5 files changed, 17 insertions(+), 36 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java index bb2d506f5..0bc339f82 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java @@ -117,18 +117,10 @@ public final class PaperweightFaweAdapter extends FaweAdapter>> allBlockProperties = null; public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { - this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R2.PaperweightAdapter(); + super(new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R2.PaperweightAdapter()); } public Function blockEntityToCompoundTag() { diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java index c4af78e95..1abfc5b04 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java @@ -117,18 +117,10 @@ public final class PaperweightFaweAdapter extends FaweAdapter>> allBlockProperties = null; public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { - this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3.PaperweightAdapter(); + super(new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3.PaperweightAdapter()); } public Function blockEntityToCompoundTag() { diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java index 151ffd1f3..692e03a94 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java @@ -126,18 +126,10 @@ public final class PaperweightFaweAdapter extends FaweAdapter>> allBlockProperties = null; public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { - this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R4.PaperweightAdapter(); + super(new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R4.PaperweightAdapter()); } public Function blockEntityToCompoundTag() { diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java index 34fc70f8d..353f6b5c1 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java @@ -126,18 +126,10 @@ public final class PaperweightFaweAdapter extends FaweAdapter>> allBlockProperties = null; public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { - this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1.PaperweightAdapter(); + super(new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1.PaperweightAdapter()); } public Function blockEntityToCompoundTag() { diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/FaweAdapter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/FaweAdapter.java index e116daf17..441cd1d87 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/FaweAdapter.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/FaweAdapter.java @@ -4,7 +4,9 @@ import com.fastasyncworldedit.core.util.TaskManager; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.TreeGenerator; import org.bukkit.Material; import org.bukkit.TreeType; @@ -12,6 +14,7 @@ import org.bukkit.World; import org.bukkit.block.BlockState; import java.util.List; +import java.util.Map; /** * A base class for version-specific implementations of the BukkitImplAdapter @@ -21,6 +24,16 @@ import java.util.List; */ public abstract class FaweAdapter extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter { + protected final BukkitImplAdapter parent; + protected char[] ibdToStateOrdinal = null; + protected int[] ordinalToIbdID = null; + protected boolean initialised = false; + protected Map>> allBlockProperties = null; + + protected FaweAdapter(final BukkitImplAdapter parent) { + this.parent = parent; + } + @Override public boolean generateTree( final TreeGenerator.TreeType treeType, From 7281fa360f52467f4e7cc2d31d1de52e940ef7f2 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Mon, 4 Nov 2024 12:22:06 +0100 Subject: [PATCH 434/466] Make property changes more robust (#2962) --- .../core/registry/state/PropertyKey.java | 5 +++++ .../sk89q/worldedit/world/block/BlockState.java | 2 +- .../sk89q/worldedit/world/block/BlockType.java | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/registry/state/PropertyKey.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/registry/state/PropertyKey.java index baba00a6b..0147d0e91 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/registry/state/PropertyKey.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/registry/state/PropertyKey.java @@ -137,4 +137,9 @@ public class PropertyKey implements Comparable { return Integer.compare(this.id, o.id); } + @Override + public String toString() { + return "PropertyKey[" + getName() + "]"; + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index 824ad2b85..95f2c2585 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -351,7 +351,7 @@ public class BlockState implements BlockStateHolder, Pattern { BlockState newState = this; for (Property prop : ot.getProperties()) { PropertyKey key = prop.getKey(); - if (blockType.hasProperty(key)) { + if (blockType.hasPropertyOfType(key, prop.getClass())) { newState = newState.with(key, other.getState(key)); } } 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 d8b0ae046..e72d0b0e3 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 @@ -247,6 +247,21 @@ public class BlockType implements Keyed, Pattern { return this.settings.propertiesMapArr.length > ordinal && this.settings.propertiesMapArr[ordinal] != null; } + /** + * {@return whether this block type has a property with given key of the given type} + * + * @param key the key identifying the property + * @param propertyType the expected type of the property + * @since TODO + */ + public boolean hasPropertyOfType(PropertyKey key, Class propertyType) { + int ordinal = key.getId(); + Property property; + return this.settings.propertiesMapArr.length > ordinal + && (property = this.settings.propertiesMapArr[ordinal]) != null + && property.getClass() == propertyType; + } + public Property getProperty(PropertyKey key) { try { return (Property) this.settings.propertiesMapArr[key.getId()]; From e55e8fabe8617b639483d84aff9207432597533f Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 6 Nov 2024 17:13:56 +0000 Subject: [PATCH 435/466] feat: improve error handling for state property operations (#2975) --- .../platform/AbstractPlayerActor.java | 6 +++++- .../extension/platform/PlatformManager.java | 18 ++++-------------- .../worldedit/world/block/BlockState.java | 15 +++++++++++++++ 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java index 5337fe720..13379f853 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 @@ -34,6 +34,7 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.internal.cui.CUIEvent; +import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.ConvexPolyhedralRegion; @@ -62,6 +63,7 @@ import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameModes; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; +import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; import java.io.File; @@ -76,6 +78,8 @@ import java.util.concurrent.atomic.AtomicInteger; */ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { + private static final Logger LOGGER = LogManagerCompat.getLogger(); + //FAWE start private final Map meta; @@ -93,7 +97,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { if (fe != null) { printError(fe.getComponent()); } else { - throwable.printStackTrace(); + LOGGER.error("Error occurred executing player action", throwable); } } }, this::getUniqueId); 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 9f798e21c..72feee18d 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 @@ -273,9 +273,7 @@ public class PlatformManager { public T createProxyActor(T base) { checkNotNull(base); - if (base instanceof Player) { - Player player = (Player) base; - + if (base instanceof Player player) { Player permActor = queryCapability(Capability.PERMISSIONS).matchPlayer(player); if (permActor == null) { permActor = player; @@ -389,10 +387,9 @@ public class PlatformManager { Location location = event.getLocation(); // At this time, only handle interaction from players - if (!(actor instanceof Player)) { + if (!(actor instanceof Player player)) { return; } - Player player = (Player) actor; LocalSession session = worldEdit.getSessionManager().get(actor); Request.reset(); @@ -463,7 +460,7 @@ public class PlatformManager { } else { actor.print(Caption.of("worldedit.command.error.report")); actor.print(TextComponent.of(e.getClass().getName()+ ": " + e.getMessage())); - e.printStackTrace(); + LOGGER.error("Error occurred executing player action", e); } } //FAWE end @@ -511,14 +508,7 @@ public class PlatformManager { } //FAWE start - add own message } catch (Throwable e) { - FaweException faweException = FaweException.get(e); - if (faweException != null) { - player.print(Caption.of("fawe.cancel.reason", faweException.getComponent())); - } else { - player.print(Caption.of("worldedit.command.error.report")); - player.print(TextComponent.of(e.getClass().getName() + ": " + e.getMessage())); - e.printStackTrace(); - } + handleThrowable(e, player); //FAWE end } finally { Request.reset(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index 95f2c2585..b6a12cb7c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -312,6 +312,11 @@ public class BlockState implements BlockStateHolder, Pattern { return newState != this.getInternalId() ? type.withStateId(newState) : this; } catch (ClassCastException e) { throw new IllegalArgumentException("Property not found: " + property); + } catch (Exception e) { + throw new UnsupportedOperationException( + "Error resolving property " + property.getName() + " for block type " + getBlockType().id() + "(nullable) value " + value, + e + ); } } @@ -322,6 +327,11 @@ public class BlockState implements BlockStateHolder, Pattern { return (V) ap.getValue(this.getInternalId()); } catch (ClassCastException e) { throw new IllegalArgumentException("Property not found: " + property); + } catch (Exception e) { + throw new UnsupportedOperationException( + "Error resolving property " + property.getName() + " for blocktype " + getBlockType().id(), + e + ); } } @@ -337,6 +347,11 @@ public class BlockState implements BlockStateHolder, Pattern { return newState != this.getInternalId() ? type.withStateId(newState) : this; } catch (ClassCastException e) { throw new IllegalArgumentException("Property not found: " + property); + } catch (Exception e) { + throw new UnsupportedOperationException( + "Error resolving property " + property.getName() + " for block type " + getBlockType().id() + "(nullable) value " + value, + e + ); } } From eb0f07af81516def23f388a5a6fd846aff9d82e5 Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 6 Nov 2024 17:16:03 +0000 Subject: [PATCH 436/466] feat: alter clipboard thread to move all clipboard loading from main thread (#2867) --- .../worldedit/bukkit/WorldEditPlugin.java | 20 ++--- .../com/fastasyncworldedit/core/Fawe.java | 63 +++++++++++++-- .../util/task/UUIDKeyQueuedThreadFactory.java | 41 ++++++++++ .../com/sk89q/worldedit/LocalSession.java | 4 +- .../worldedit/command/ClipboardCommands.java | 2 +- .../com/sk89q/worldedit/entity/Player.java | 30 +------ .../platform/AbstractPlayerActor.java | 80 +++++++++++++++---- .../src/main/resources/lang/strings.json | 2 +- 8 files changed, 181 insertions(+), 61 deletions(-) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/util/task/UUIDKeyQueuedThreadFactory.java 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 faac1c955..f676ae07b 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 @@ -564,17 +564,17 @@ public class WorldEditPlugin extends JavaPlugin { public BukkitPlayer wrapPlayer(Player player) { //FAWE start - Use cache over returning a direct BukkitPlayer BukkitPlayer wePlayer = getCachedPlayer(player); - if (wePlayer == null) { - synchronized (player) { - wePlayer = getCachedPlayer(player); - if (wePlayer == null) { - wePlayer = new BukkitPlayer(this, player); - player.setMetadata("WE", new FixedMetadataValue(this, wePlayer)); - return wePlayer; - } - } + if (wePlayer != null) { + return wePlayer; + } + synchronized (player) { + BukkitPlayer bukkitPlayer = getCachedPlayer(player); + if (bukkitPlayer == null) { + bukkitPlayer = new BukkitPlayer(this, player); + player.setMetadata("WE", new FixedMetadataValue(this, bukkitPlayer)); + } + return bukkitPlayer; } - return wePlayer; //FAWE end } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java index dac6fe9d6..6238ea1ea 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java @@ -14,8 +14,8 @@ import com.fastasyncworldedit.core.util.TaskManager; import com.fastasyncworldedit.core.util.TextureUtil; import com.fastasyncworldedit.core.util.WEManager; import com.fastasyncworldedit.core.util.task.KeyQueuedExecutorService; +import com.fastasyncworldedit.core.util.task.UUIDKeyQueuedThreadFactory; import com.github.luben.zstd.Zstd; -import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.internal.util.LogManagerCompat; import net.jpountz.lz4.LZ4Factory; @@ -37,6 +37,9 @@ import java.lang.management.MemoryUsage; import java.util.Date; import java.util.List; import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -92,7 +95,7 @@ public class Fawe { * The platform specific implementation. */ private final IFawe implementation; - private final KeyQueuedExecutorService clipboardExecutor; + private final KeyQueuedExecutorService uuidKeyQueuedExecutorService; private FaweVersion version; private TextureUtil textures; private QueueHandler queueHandler; @@ -140,14 +143,13 @@ public class Fawe { }, 0); TaskManager.taskManager().repeat(timer, 1); - - clipboardExecutor = new KeyQueuedExecutorService<>(new ThreadPoolExecutor( + uuidKeyQueuedExecutorService = new KeyQueuedExecutorService<>(new ThreadPoolExecutor( 1, Settings.settings().QUEUE.PARALLEL_THREADS, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), - new ThreadFactoryBuilder().setNameFormat("FAWE Clipboard - %d").build() + new UUIDKeyQueuedThreadFactory() )); } @@ -463,9 +465,58 @@ public class Fawe { * * @return Executor used for clipboard IO if clipboard on disk is enabled or null * @since 2.6.2 + * @deprecated Use any of {@link Fawe#submitUUIDKeyQueuedTask(UUID, Runnable)}, + * {@link Fawe#submitUUIDKeyQueuedTask(UUID, Runnable, Object), {@link Fawe#submitUUIDKeyQueuedTask(UUID, Callable)} + * to ensure if a thread is already a UUID-queued thread, the task is immediately run */ + @Deprecated(forRemoval = true, since = "TODO") public KeyQueuedExecutorService getClipboardExecutor() { - return this.clipboardExecutor; + return this.uuidKeyQueuedExecutorService; + } + + /** + * Submit a task to the UUID key-queued executor + * + * @return Future representing the tank + * @since TODO + */ + public Future submitUUIDKeyQueuedTask(UUID uuid, Runnable runnable) { + if (Thread.currentThread() instanceof UUIDKeyQueuedThreadFactory.UUIDKeyQueuedThread) { + runnable.run(); + return CompletableFuture.completedFuture(null); + } + return this.uuidKeyQueuedExecutorService.submit(uuid, runnable); + } + + /** + * Submit a task to the UUID key-queued executor + * + * @return Future representing the tank + * @since TODO + */ + public Future submitUUIDKeyQueuedTask(UUID uuid, Runnable runnable, T result) { + if (Thread.currentThread() instanceof UUIDKeyQueuedThreadFactory.UUIDKeyQueuedThread) { + runnable.run(); + return CompletableFuture.completedFuture(result); + } + return this.uuidKeyQueuedExecutorService.submit(uuid, runnable, result); + } + + /** + * Submit a task to the UUID key-queued executor + * + * @return Future representing the tank + * @since TODO + */ + public Future submitUUIDKeyQueuedTask(UUID uuid, Callable callable) { + if (Thread.currentThread() instanceof UUIDKeyQueuedThreadFactory.UUIDKeyQueuedThread) { + try { + return CompletableFuture.completedFuture(callable.call()); + } catch (Throwable t) { + return CompletableFuture.failedFuture(t); + } + } + return this.uuidKeyQueuedExecutorService.submit(uuid, callable); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/task/UUIDKeyQueuedThreadFactory.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/task/UUIDKeyQueuedThreadFactory.java new file mode 100644 index 000000000..2e87b8c25 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/task/UUIDKeyQueuedThreadFactory.java @@ -0,0 +1,41 @@ +package com.fastasyncworldedit.core.util.task; + +import org.jetbrains.annotations.ApiStatus; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +@ApiStatus.Internal +public class UUIDKeyQueuedThreadFactory implements ThreadFactory { + + private final ThreadGroup group; + private final AtomicInteger threadNumber = new AtomicInteger(1); + private final String namePrefix; + + public UUIDKeyQueuedThreadFactory() { + group = new ThreadGroup("UUIDKeyQueuedThreadGroup"); + namePrefix = "FAWE UUID-key-queued - "; + } + + public Thread newThread(@Nonnull Runnable r) { + Thread t = new UUIDKeyQueuedThread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); + if (t.isDaemon()) { + t.setDaemon(false); + } + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + return t; + } + + public static final class UUIDKeyQueuedThread extends Thread { + + public UUIDKeyQueuedThread(@Nullable ThreadGroup group, Runnable task, @Nonnull String name, long stackSize) { + super(group, task, name, stackSize); + } + + } + +} 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 51a03119f..006de1b0b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -930,7 +930,7 @@ public class LocalSession implements TextureHolder { } } catch (EmptyClipboardException ignored) { } - DiskOptimizedClipboard doc = Fawe.instance().getClipboardExecutor().submit( + DiskOptimizedClipboard doc = Fawe.instance().submitUUIDKeyQueuedTask( uuid, () -> DiskOptimizedClipboard.loadFromFile(file) ).get(); @@ -954,7 +954,7 @@ public class LocalSession implements TextureHolder { } else { continue; } - Fawe.instance().getClipboardExecutor().submit(uuid, () -> { + Fawe.instance().submitUUIDKeyQueuedTask(uuid, () -> { doc.close(); // Ensure closed before deletion doc.getFile().delete(); }); 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 bb42e7095..a424682fe 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 @@ -325,7 +325,7 @@ public class ClipboardCommands { } else { throw e; } - Fawe.instance().getClipboardExecutor().submit(actor.getUniqueId(), () -> { + Fawe.instance().submitUUIDKeyQueuedTask(actor.getUniqueId(), () -> { clipboard.close(); doc.getFile().delete(); }); 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 cc203190b..11561f313 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 @@ -423,7 +423,7 @@ public interface Player extends Entity, Actor { if (Settings.settings().CLIPBOARD.USE_DISK && Settings.settings().CLIPBOARD.DELETE_ON_LOGOUT) { session.deleteClipboardOnDisk(); } else if (Settings.settings().CLIPBOARD.USE_DISK) { - Fawe.instance().getClipboardExecutor().submit(getUniqueId(), () -> session.setClipboard(null)); + Fawe.instance().submitUUIDKeyQueuedTask(getUniqueId(), () -> session.setClipboard(null)); } else if (Settings.settings().CLIPBOARD.DELETE_ON_LOGOUT) { session.setClipboard(null); } @@ -436,32 +436,8 @@ public interface Player extends Entity, Actor { void sendTitle(Component title, Component sub); /** - * Loads any history items from disk: - Should already be called if history on disk is enabled. + * Loads clipboard file from disk if it exists */ - default void loadClipboardFromDisk() { - File file = MainUtil.getFile( - Fawe.platform().getDirectory(), - Settings.settings().PATHS.CLIPBOARD + File.separator + getUniqueId() + ".bd" - ); - try { - getSession().loadClipboardFromDisk(file); - } catch (FaweClipboardVersionMismatchException e) { - print(e.getComponent()); - } catch (RuntimeException e) { - print(Caption.of("fawe.error.clipboard.invalid")); - e.printStackTrace(); - print(Caption.of("fawe.error.stacktrace")); - print(Caption.of("fawe.error.clipboard.load.failure")); - print(Caption.of("fawe.error.clipboard.invalid.info", file.getName(), file.length())); - print(Caption.of("fawe.error.stacktrace")); - } catch (Exception e) { - print(Caption.of("fawe.error.clipboard.invalid")); - e.printStackTrace(); - print(Caption.of("fawe.error.stacktrace")); - print(Caption.of("fawe.error.no-failure")); - print(Caption.of("fawe.error.clipboard.invalid.info", file.getName(), file.length())); - print(Caption.of("fawe.error.stacktrace")); - } - } + void loadClipboardFromDisk(); //FAWE end } 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 13379f853..23b3799ef 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,10 +19,14 @@ package com.sk89q.worldedit.extension.platform; +import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.internal.exception.FaweClipboardVersionMismatchException; import com.fastasyncworldedit.core.internal.exception.FaweException; import com.fastasyncworldedit.core.math.MutableBlockVector3; import com.fastasyncworldedit.core.regions.FaweMaskManager; +import com.fastasyncworldedit.core.util.MainUtil; import com.fastasyncworldedit.core.util.TaskManager; import com.fastasyncworldedit.core.util.WEManager; import com.fastasyncworldedit.core.util.task.AsyncNotifyKeyedQueue; @@ -69,6 +73,8 @@ import javax.annotation.Nullable; import java.io.File; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Future; +import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicInteger; /** @@ -82,6 +88,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { //FAWE start private final Map meta; + private final Semaphore clipboardLoading = new Semaphore(1); // Queue for async tasks private final AtomicInteger runningCount = new AtomicInteger(); @@ -524,22 +531,68 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public void setSelection(Region region) { - RegionSelector selector; - if (region instanceof ConvexPolyhedralRegion) { - selector = new ConvexPolyhedralRegionSelector((ConvexPolyhedralRegion) region); - } else if (region instanceof CylinderRegion) { - selector = new CylinderRegionSelector((CylinderRegion) region); - } else if (region instanceof Polygonal2DRegion) { - selector = new Polygonal2DRegionSelector((Polygonal2DRegion) region); - } else { - selector = new CuboidRegionSelector(null, region.getMinimumPoint(), - region.getMaximumPoint() - ); - } + RegionSelector selector = switch (region) { + case ConvexPolyhedralRegion blockVector3s -> new ConvexPolyhedralRegionSelector(blockVector3s); + case CylinderRegion blockVector3s -> new CylinderRegionSelector(blockVector3s); + case Polygonal2DRegion blockVector3s -> new Polygonal2DRegionSelector(blockVector3s); + default -> new CuboidRegionSelector(null, region.getMinimumPoint(), region.getMaximumPoint()); + }; selector.setWorld(region.getWorld()); getSession().setRegionSelector(getWorld(), selector); } + + @Override + public void loadClipboardFromDisk() { + if (!clipboardLoading.tryAcquire()) { + if (!Fawe.isMainThread()) { + try { + clipboardLoading.acquire(); + clipboardLoading.release(); + } catch (InterruptedException e) { + LOGGER.error("Error waiting for clipboard-on-disk loading for player {}", getName(), e); + } + } + return; + } + + File file = MainUtil.getFile( + Fawe.platform().getDirectory(), + Settings.settings().PATHS.CLIPBOARD + File.separator + getUniqueId() + ".bd" + ); + try { + Future fut = Fawe.instance().submitUUIDKeyQueuedTask(getUniqueId(), () -> { + try { + getSession().loadClipboardFromDisk(file); + } catch (FaweClipboardVersionMismatchException e) { + print(e.getComponent()); + } catch (RuntimeException e) { + print(Caption.of("fawe.error.clipboard.invalid")); + LOGGER.error("Error loading clipboard from disk", e); + print(Caption.of("fawe.error.stacktrace")); + print(Caption.of("fawe.error.clipboard.load.failure")); + print(Caption.of("fawe.error.clipboard.invalid.info", file.getName(), file.length())); + print(Caption.of("fawe.error.stacktrace")); + } catch (Exception e) { + print(Caption.of("fawe.error.clipboard.invalid")); + LOGGER.error("Error loading clipboard from disk", e); + print(Caption.of("fawe.error.stacktrace")); + print(Caption.of("fawe.error.no-failure")); + print(Caption.of("fawe.error.clipboard.invalid.info", file.getName(), file.length())); + print(Caption.of("fawe.error.stacktrace")); + } finally { + clipboardLoading.release(); + } + }); + if (Fawe.isMainThread()) { + return; + } + fut.get(); + } catch (Exception e) { + LOGGER.error("Error loading clipboard from disk", e); + print(Caption.of("fawe.error.clipboard.load.failure")); + } + } //FAWE end @Override @@ -698,10 +751,9 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public boolean equals(Object other) { - if (!(other instanceof Player)) { + if (!(other instanceof Player other2)) { return false; } - Player other2 = (Player) other; return other2.getName().equals(getName()); } diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index 0b7a63b8d..c3468f9d8 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -132,7 +132,7 @@ "fawe.error.parse.no-clipboard-source": "No clipboards found at given source: {0}", "fawe.error.clipboard.invalid": "====== INVALID CLIPBOARD ======", "fawe.error.clipboard.invalid.info": "File: {0} (len: {1})", - "fawe.error.clipboard.load.failure": "Could not load clipboard. Possible that the clipboard is still being written to from another server?!", + "fawe.error.clipboard.load.failure": "Unexpected failure loading clipboard from disk!", "fawe.error.clipboard.on.disk.version.mismatch": "Clipboard version mismatch: expected {0} but got {1}. It is recommended you delete the clipboard folder and restart the server.\nYour clipboard folder is located at {2}.", "fawe.error.limit.disallowed-block": "Your limit disallows use of block '{0}'", "fawe.error.limit.disallowed-property": "Your limit disallows use of property '{0}'", From ef8426473a224d3b28ff0c7a1a179d047b130d47 Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Sun, 10 Nov 2024 19:13:16 +0100 Subject: [PATCH 437/466] 1.21.3 (#2974) * feat: initial work on 1.21.3 adapter * chore: method does not exist anymore * cleanup, deduplicate, drop old versions from runServer task * chore: apply deduplicated fields changes from PR * chore: remove jetbrains annotations references * chore: remove unsupported versions from modrinth release task * chore: adjust mondrinth versions, update issue template --- .github/ISSUE_TEMPLATE/bug_report.yml | 3 +- build.gradle.kts | 4 +- gradle/libs.versions.toml | 2 +- settings.gradle.kts | 2 +- .../adapters/adapter-1_21_3/build.gradle.kts | 17 + .../ext/fawe/v1_21_3/PaperweightAdapter.java | 1121 +++++++ .../v1_21_3/PaperweightDataConverters.java | 2795 +++++++++++++++++ .../fawe/v1_21_3/PaperweightFakePlayer.java | 87 + .../v1_21_3/PaperweightWorldNativeAccess.java | 192 ++ .../ext/fawe/v1_21_3/StaticRefraction.java | 84 + .../v1_21_3/PaperweightBlockMaterial.java | 175 ++ .../fawe/v1_21_3/PaperweightFaweAdapter.java | 619 ++++ .../PaperweightFaweWorldNativeAccess.java | 294 ++ .../fawe/v1_21_3/PaperweightGetBlocks.java | 1199 +++++++ .../v1_21_3/PaperweightGetBlocks_Copy.java | 276 ++ .../fawe/v1_21_3/PaperweightMapChunkUtil.java | 34 + .../v1_21_3/PaperweightPlatformAdapter.java | 717 +++++ .../v1_21_3/PaperweightPostProcessor.java | 175 ++ .../PaperweightStarlightRelighter.java | 80 + .../PaperweightStarlightRelighterFactory.java | 25 + .../fawe/v1_21_3/regen/PaperweightRegen.java | 298 ++ worldedit-bukkit/build.gradle.kts | 2 +- .../sk89q/wepif/TestOfflinePermissible.java | 6 + 23 files changed, 8201 insertions(+), 6 deletions(-) create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightAdapter.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightDataConverters.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightFakePlayer.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightWorldNativeAccess.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/StaticRefraction.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightBlockMaterial.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightFaweAdapter.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightFaweWorldNativeAccess.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightGetBlocks.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightGetBlocks_Copy.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightMapChunkUtil.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightPlatformAdapter.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightPostProcessor.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightStarlightRelighter.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightStarlightRelighterFactory.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/regen/PaperweightRegen.java diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index c223aae35..e5da90873 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -27,7 +27,8 @@ body: description: Which server version version you using? If your server version is not listed, it is not supported. Update to a supported version first. multiple: false options: - - '1.21' + - '1.21.3' + - '1.21.1' - '1.20.6' - '1.20.4' - '1.20.2' diff --git a/build.gradle.kts b/build.gradle.kts index 824a50ad1..aa979af3f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -83,7 +83,7 @@ allprojects { } applyCommonConfiguration() -val supportedVersions = listOf("1.19.4", "1.20", "1.20.4", "1.20.5", "1.20.6", "1.21", "1.21.1") +val supportedVersions = listOf("1.20.4", "1.20.5", "1.20.6", "1.21", "1.21.1", "1.21.3") tasks { supportedVersions.forEach { @@ -97,7 +97,7 @@ tasks { } } runServer { - minecraftVersion("1.21.1") + minecraftVersion("1.21.3") pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile } .toTypedArray()) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2730e6df3..7c9552c71 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] # Minecraft expectations -paper = "1.21-R0.1-SNAPSHOT" +paper = "1.21.3-R0.1-SNAPSHOT" fastutil = "8.5.9" guava = "31.1-jre" log4j = "2.19.0" diff --git a/settings.gradle.kts b/settings.gradle.kts index 4e1b292c5..d724e7a4e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,7 +2,7 @@ rootProject.name = "FastAsyncWorldEdit" include("worldedit-libs") -listOf("1_20_2", "1_20_4", "1_20_5", "1_21").forEach { +listOf("1_20_2", "1_20_4", "1_20_5", "1_21", "1_21_3").forEach { include("worldedit-bukkit:adapters:adapter-$it") } diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts new file mode 100644 index 000000000..39c94c40b --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts @@ -0,0 +1,17 @@ +import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension + +plugins { + java +} + +applyPaperweightAdapterConfiguration() + +repositories { + gradlePluginPortal() +} + +dependencies { + // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.3-R0.1-SNAPSHOT/ + the().paperDevBundle("1.21.3-R0.1-20241101.150401-13") + compileOnly(libs.paperlib) +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightAdapter.java new file mode 100644 index 000000000..6d61641d7 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightAdapter.java @@ -0,0 +1,1121 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_3; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.google.common.util.concurrent.Futures; +import com.mojang.serialization.Codec; +import com.mojang.serialization.Lifecycle; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_3.PaperweightFaweAdapter; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extension.platform.Watchdog; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.util.io.file.SafeFiles; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.RegenOptions; +import com.sk89q.worldedit.world.biome.BiomeCategory; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.item.ItemType; +import net.minecraft.SharedConstants; +import net.minecraft.Util; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.Registry; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ChunkResult; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.util.thread.BlockableEventLoop; +import net.minecraft.world.Clearable; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelSettings; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.StructureBlockEntity; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.WorldOptions; +import net.minecraft.world.level.storage.LevelStorageSource; +import net.minecraft.world.level.storage.PrimaryLevelData; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.World.Environment; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; +import org.bukkit.generator.ChunkGenerator; +import org.enginehub.linbus.common.LinTagId; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinByteTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinEndTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinLongArrayTag; +import org.enginehub.linbus.tree.LinLongTag; +import org.enginehub.linbus.tree.LinShortTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; +import org.spigotmc.SpigotConfig; +import org.spigotmc.WatchdogThread; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.OptionalInt; +import java.util.OptionalLong; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +public final class PaperweightAdapter implements BukkitImplAdapter { + + private final Logger logger = Logger.getLogger(getClass().getCanonicalName()); + + private final Field serverWorldsField; + private final Method getChunkFutureMethod; + private final Field chunkProviderExecutorField; + private final PaperweightDataConverters dataFixer; + private final Watchdog watchdog; + + // ------------------------------------------------------------------------ + // Code that may break between versions of Minecraft + // ------------------------------------------------------------------------ + + public PaperweightAdapter() throws NoSuchFieldException, NoSuchMethodException { + // A simple test + CraftServer.class.cast(Bukkit.getServer()); + + int dataVersion = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); + if (dataVersion != 4082) { + throw new UnsupportedClassVersionError("Not 1.21.3!"); + } + + serverWorldsField = CraftServer.class.getDeclaredField("worlds"); + serverWorldsField.setAccessible(true); + + getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod( + StaticRefraction.GET_CHUNK_FUTURE_MAIN_THREAD, + int.class, int.class, ChunkStatus.class, boolean.class + ); + getChunkFutureMethod.setAccessible(true); + + chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField( + StaticRefraction.MAIN_THREAD_PROCESSOR + ); + chunkProviderExecutorField.setAccessible(true); + + this.dataFixer = new PaperweightDataConverters(dataVersion, this); + + Watchdog watchdog; + try { + Class.forName("org.spigotmc.WatchdogThread"); + watchdog = new SpigotWatchdog(); + } catch (ClassNotFoundException | NoSuchFieldException e) { + try { + watchdog = new MojangWatchdog(((CraftServer) Bukkit.getServer()).getServer()); + } catch (NoSuchFieldException ex) { + watchdog = null; + } + } + this.watchdog = watchdog; + + try { + Class.forName("org.spigotmc.SpigotConfig"); + SpigotConfig.config.set("world-settings.worldeditregentempworld.verbose", false); + } catch (ClassNotFoundException ignored) { + } + } + + @Override + public DataFixer getDataFixer() { + return this.dataFixer; + } + + /** + * Read the given NBT data into the given tile entity. + * + * @param tileEntity the tile entity + * @param tag the tag + */ + static void readTagIntoTileEntity(net.minecraft.nbt.CompoundTag tag, BlockEntity tileEntity) { + tileEntity.loadWithComponents(tag, MinecraftServer.getServer().registryAccess()); + tileEntity.setChanged(); + } + + /** + * Get the ID string of the given entity. + * + * @param entity the entity + * @return the entity ID + */ + private static String getEntityId(Entity entity) { + return EntityType.getKey(entity.getType()).toString(); + } + + /** + * Create an entity using the given entity ID. + * + * @param id the entity ID + * @param world the world + * @return an entity or null + */ + @Nullable + private static Entity createEntityFromId(String id, net.minecraft.world.level.Level world) { + return EntityType.byString(id).map(t -> t.create(world, EntitySpawnReason.COMMAND)).orElse(null); + } + + /** + * Write the given NBT data into the given entity. + * + * @param entity the entity + * @param tag the tag + */ + private static void readTagIntoEntity(net.minecraft.nbt.CompoundTag tag, Entity entity) { + entity.load(tag); + } + + /** + * Write the entity's NBT data to the given tag. + * + * @param entity the entity + * @param tag the tag + */ + private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag tag) { + entity.save(tag); + } + + private static Block getBlockFromType(BlockType blockType) { + return DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.BLOCK).getValue(ResourceLocation.tryParse(blockType.id())); + } + + private static Item getItemFromType(ItemType itemType) { + return DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.ITEM).getValue(ResourceLocation.tryParse(itemType.id())); + } + + @Override + public OptionalInt getInternalBlockStateId(BlockData data) { + net.minecraft.world.level.block.state.BlockState state = ((CraftBlockData) data).getState(); + int combinedId = Block.getId(state); + return combinedId == 0 && state.getBlock() != Blocks.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); + } + + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + Block mcBlock = getBlockFromType(state.getBlockType()); + net.minecraft.world.level.block.state.BlockState newState = mcBlock.defaultBlockState(); + Map, Object> states = state.getStates(); + newState = applyProperties(mcBlock.getStateDefinition(), newState, states); + final int combinedId = Block.getId(newState); + return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); + } + + public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) { + int internalId = Block.getId(blockState); + BlockState state = BlockStateIdAccess.getBlockStateById(internalId); + if (state == null) { + state = BukkitAdapter.adapt(CraftBlockData.createData(blockState)); + } + + return state; + } + + public BiomeType adapt(Biome biome) { + var mcBiome = ((CraftServer) Bukkit.getServer()).getServer().registryAccess() + .lookupOrThrow(Registries.BIOME).getKey(biome); + if (mcBiome == null) { + return null; + } + return BiomeType.REGISTRY.get(mcBiome.toString()); + } + + public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockState) { + int internalId = BlockStateIdAccess.getBlockStateId(blockState); + return Block.stateById(internalId); + } + + @Override + public BlockState getBlock(Location location) { + checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); + return adapt(blockData); + } + + @Override + public BaseBlock getFullBlock(Location location) { + BlockState state = getBlock(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + + // Read the NBT data + BlockEntity te = chunk.getBlockEntity(blockPos); + if (te != null) { + net.minecraft.nbt.CompoundTag tag = te.saveWithId(MinecraftServer.getServer().registryAccess()); + return state.toBaseBlock(LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag))); + } + + return state.toBaseBlock(); + } + + private static final HashMap> biomeTypeToNMSCache = new HashMap<>(); + private static final HashMap, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); + + @Override + public BiomeType getBiome(Location location) { + checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + + return biomeTypeFromNMSCache.computeIfAbsent(chunk.getNoiseBiome(x >> 2, y >> 2, z >> 2), + b -> BiomeType.REGISTRY.get(b.unwrapKey().orElseThrow().location().toString())); + } + + @Override + public void setBiome(Location location, BiomeType biome) { + checkNotNull(location); + checkNotNull(biome); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + chunk.setBiome(x >> 2, y >> 2, z >> 2, biomeTypeToNMSCache.computeIfAbsent(biome, + b -> handle.registryAccess().lookupOrThrow(Registries.BIOME) + .getOrThrow(ResourceKey.create(Registries.BIOME, ResourceLocation.parse(b.id()))))); + chunk.markUnsaved(); + } + + @Override + public WorldNativeAccess createWorldNativeAccess(World world) { + return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle())); + } + + private static net.minecraft.core.Direction adapt(Direction face) { + switch (face) { + case NORTH: + return net.minecraft.core.Direction.NORTH; + case SOUTH: + return net.minecraft.core.Direction.SOUTH; + case WEST: + return net.minecraft.core.Direction.WEST; + case EAST: + return net.minecraft.core.Direction.EAST; + case DOWN: + return net.minecraft.core.Direction.DOWN; + case UP: + default: + return net.minecraft.core.Direction.UP; + } + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private net.minecraft.world.level.block.state.BlockState applyProperties( + StateDefinition stateContainer, + net.minecraft.world.level.block.state.BlockState newState, + Map, Object> states + ) { + for (Map.Entry, Object> state : states.entrySet()) { + net.minecraft.world.level.block.state.properties.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 net.minecraft.world.level.block.state.properties.EnumProperty enumProperty) { + if (enumProperty.getValueClass() == net.minecraft.core.Direction.class) { + value = adapt((Direction) value); + } else { + String enumName = (String) value; + value = ((net.minecraft.world.level.block.state.properties.EnumProperty) property) + .getValue(enumName).orElseThrow(() -> + new IllegalStateException( + "Enum property " + property.getName() + " does not contain " + enumName + ) + ); + } + } + newState = newState.setValue( + (net.minecraft.world.level.block.state.properties.Property) property, + (Comparable) value + ); + } + return newState; + } + + @Override + public BaseEntity getEntity(org.bukkit.entity.Entity entity) { + checkNotNull(entity); + + CraftEntity craftEntity = ((CraftEntity) entity); + Entity mcEntity = craftEntity.getHandle(); + + // Do not allow creating of passenger entity snapshots, passengers are included in the vehicle entity + if (mcEntity.isPassenger()) { + return null; + } + + String id = getEntityId(mcEntity); + + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + readEntityIntoTag(mcEntity, tag); + return new BaseEntity( + EntityTypes.get(id), + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) + ); + } + + @Nullable + @Override + public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state) { + checkNotNull(location); + checkNotNull(state); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + ServerLevel worldServer = craftWorld.getHandle(); + + String entityId = state.getType().id(); + + LinCompoundTag nativeTag = state.getNbt(); + net.minecraft.nbt.CompoundTag tag; + if (nativeTag != null) { + tag = (net.minecraft.nbt.CompoundTag) fromNativeLin(nativeTag); + removeUnwantedEntityTagsRecursively(tag); + } else { + tag = new net.minecraft.nbt.CompoundTag(); + } + + tag.putString("id", entityId); + + Entity createdEntity = EntityType.loadEntityRecursive(tag, craftWorld.getHandle(), EntitySpawnReason.COMMAND, (loadedEntity) -> { + loadedEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + return loadedEntity; + }); + + if (createdEntity != null) { + worldServer.addFreshEntityWithPassengers(createdEntity, SpawnReason.CUSTOM); + return createdEntity.getBukkitEntity(); + } else { + return null; + } + } + + // This removes all unwanted tags from the main entity and all its passengers + private void removeUnwantedEntityTagsRecursively(net.minecraft.nbt.CompoundTag tag) { + for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + + // Adapted from net.minecraft.world.entity.EntityType#loadEntityRecursive + if (tag.contains("Passengers", LinTagId.LIST.id())) { + net.minecraft.nbt.ListTag nbttaglist = tag.getList("Passengers", LinTagId.COMPOUND.id()); + + for (int i = 0; i < nbttaglist.size(); ++i) { + removeUnwantedEntityTagsRecursively(nbttaglist.getCompound(i)); + } + } + } + + @Override + public Component getRichBlockName(BlockType blockType) { + return TranslatableComponent.of(getBlockFromType(blockType).getDescriptionId()); + } + + @Override + public Component getRichItemName(ItemType itemType) { + return TranslatableComponent.of(getItemFromType(itemType).getDescriptionId()); + } + + @Override + public Component getRichItemName(BaseItemStack itemStack) { + return TranslatableComponent.of(CraftItemStack.asNMSCopy(BukkitAdapter.adapt(itemStack)).getItem().getDescriptionId()); + } + + private static final LoadingCache, Property> PROPERTY_CACHE = + CacheBuilder.newBuilder().build(CacheLoader.from(PaperweightFaweAdapter::adaptProperty)); + + @SuppressWarnings({ "rawtypes" }) + @Override + public Map> getProperties(BlockType blockType) { + Map> properties = new TreeMap<>(); + Block block = getBlockFromType(blockType); + StateDefinition blockStateList = + block.getStateDefinition(); + for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { + Property property = PROPERTY_CACHE.getUnchecked(state); + properties.put(property.getName(), property); + } + return properties; + } + + @Override + public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) { + var structureBlock = new StructureBlockEntity( + new BlockPos(pos.x(), pos.y(), pos.z()), + Blocks.STRUCTURE_BLOCK.defaultBlockState() + ); + structureBlock.setLevel(((CraftPlayer) player).getHandle().level()); + ((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create( + structureBlock, + (blockEntity, registryAccess) -> (net.minecraft.nbt.CompoundTag) fromNativeLin(nbtData) + )); + } + + @Override + public void sendFakeOP(Player player) { + ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( + ((CraftPlayer) player).getHandle(), (byte) 28 + )); + } + + /** + * For serializing and deserializing components. + */ + private static final Codec COMPONENTS_CODEC = DataComponentPatch.CODEC.optionalFieldOf( + "components", DataComponentPatch.EMPTY + ).codec(); + + @Override + public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { + var registryAccess = DedicatedServer.getServer().registryAccess(); + ItemStack stack = new ItemStack( + registryAccess.lookupOrThrow(Registries.ITEM).getOrThrow( + ResourceKey.create(Registries.ITEM, ResourceLocation.parse(baseItemStack.getType().id())) + ), + baseItemStack.getAmount() + ); + LinCompoundTag nbt = baseItemStack.getNbt(); + if (nbt != null) { + DataComponentPatch componentPatch = COMPONENTS_CODEC.parse( + registryAccess.createSerializationContext(NbtOps.INSTANCE), + fromNativeLin(nbt) + ).getOrThrow(); + stack.applyComponents(componentPatch); + } + return CraftItemStack.asCraftMirror(stack); + } + + @Override + public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { + var registryAccess = DedicatedServer.getServer().registryAccess(); + final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); + CompoundTag tag = (CompoundTag) COMPONENTS_CODEC.encodeStart( + registryAccess.createSerializationContext(NbtOps.INSTANCE), + nmsStack.getComponentsPatch() + ).getOrThrow(); + return new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)), itemStack.getAmount()); + } + + private final LoadingCache fakePlayers + = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); + + @Override + public boolean simulateItemUse(World world, BlockVector3 position, BaseItem item, Direction face) { + CraftWorld craftWorld = (CraftWorld) world; + ServerLevel worldServer = craftWorld.getHandle(); + ItemStack stack = CraftItemStack.asNMSCopy(adapt( + item instanceof BaseItemStack + ? ((BaseItemStack) item) + : new BaseItemStack(item.getType(), item.getNbtReference(), 1) + )); + + PaperweightFakePlayer fakePlayer; + try { + fakePlayer = fakePlayers.get(worldServer); + } catch (ExecutionException ignored) { + return false; + } + fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); + fakePlayer.absMoveTo(position.x(), position.y(), position.z(), + (float) face.toVector().toYaw(), (float) face.toVector().toPitch()); + + final BlockPos blockPos = new BlockPos(position.x(), position.y(), position.z()); + final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos); + final net.minecraft.core.Direction enumFacing = adapt(face); + BlockHitResult rayTrace = new BlockHitResult(blockVec, enumFacing, blockPos, false); + UseOnContext context = new UseOnContext(fakePlayer, InteractionHand.MAIN_HAND, rayTrace); + InteractionResult result = stack.useOn(context); + if (result != InteractionResult.SUCCESS) { + if (worldServer.getBlockState(blockPos).useItemOn(stack, worldServer, fakePlayer, InteractionHand.MAIN_HAND, rayTrace).consumesAction()) { + result = InteractionResult.SUCCESS; + } else { + result = stack.getItem().use(worldServer, fakePlayer, InteractionHand.MAIN_HAND); + } + } + + return result == InteractionResult.SUCCESS; + } + + @Override + public boolean canPlaceAt(World world, BlockVector3 position, BlockState blockState) { + int internalId = BlockStateIdAccess.getBlockStateId(blockState); + net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId); + return blockData.canSurvive(((CraftWorld) world).getHandle(), new BlockPos(position.x(), position.y(), position.z())); + } + + @Override + public boolean regenerate(World bukkitWorld, Region region, Extent extent, RegenOptions options) { + try { + doRegen(bukkitWorld, region, extent, options); + } catch (Exception e) { + throw new IllegalStateException("Regen failed.", e); + } + + return true; + } + + private void doRegen(World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { + Environment env = bukkitWorld.getEnvironment(); + ChunkGenerator gen = bukkitWorld.getGenerator(); + + Path tempDir = Files.createTempDirectory("WorldEditWorldGen"); + LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir); + ResourceKey worldDimKey = getWorldDimKey(env); + try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("worldeditregentempworld", worldDimKey)) { + ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); + PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() + .getWorldData().overworldData(); + WorldOptions originalOpts = levelProperties.worldGenOptions(); + + long seed = options.getSeed().orElse(originalWorld.getSeed()); + WorldOptions newOpts = options.getSeed().isPresent() + ? originalOpts.withSeed(OptionalLong.of(seed)) + : originalOpts; + + LevelSettings newWorldSettings = new LevelSettings( + "worldeditregentempworld", + levelProperties.settings.gameType(), + levelProperties.settings.hardcore(), + levelProperties.settings.difficulty(), + levelProperties.settings.allowCommands(), + levelProperties.settings.gameRules(), + levelProperties.settings.getDataConfiguration() + ); + + @SuppressWarnings("deprecation") + PrimaryLevelData.SpecialWorldProperty specialWorldProperty = + levelProperties.isFlatWorld() + ? PrimaryLevelData.SpecialWorldProperty.FLAT + : levelProperties.isDebugWorld() + ? PrimaryLevelData.SpecialWorldProperty.DEBUG + : PrimaryLevelData.SpecialWorldProperty.NONE; + + PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable()); + + ServerLevel freshWorld = new ServerLevel( + originalWorld.getServer(), + originalWorld.getServer().executor, + session, newWorldData, + originalWorld.dimension(), + new LevelStem( + originalWorld.dimensionTypeRegistration(), + originalWorld.getChunkSource().getGenerator() + ), + new NoOpWorldLoadListener(), + originalWorld.isDebug(), + seed, + ImmutableList.of(), + false, + originalWorld.getRandomSequences(), + env, + gen, + bukkitWorld.getBiomeProvider() + ); + try { + regenForWorld(region, extent, freshWorld, options); + } finally { + freshWorld.getChunkSource().close(false); + } + } finally { + try { + @SuppressWarnings("unchecked") + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); + map.remove("worldeditregentempworld"); + } catch (IllegalAccessException ignored) { + } + SafeFiles.tryHardToDeleteDir(tempDir); + } + } + + private BiomeType adapt(ServerLevel serverWorld, Biome origBiome) { + ResourceLocation key = serverWorld.registryAccess().lookupOrThrow(Registries.BIOME).getKey(origBiome); + if (key == null) { + return null; + } + return BiomeTypes.get(key.toString()); + } + + @SuppressWarnings("unchecked") + private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld, RegenOptions options) throws WorldEditException { + List> chunkLoadings = submitChunkLoadTasks(region, serverWorld); + BlockableEventLoop executor; + try { + executor = (BlockableEventLoop) chunkProviderExecutorField.get(serverWorld.getChunkSource()); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Couldn't get executor for chunk loading.", e); + } + executor.managedBlock(() -> { + // bail out early if a future fails + if (chunkLoadings.stream().anyMatch(ftr -> + ftr.isDone() && Futures.getUnchecked(ftr) == null + )) { + return false; + } + return chunkLoadings.stream().allMatch(CompletableFuture::isDone); + }); + Map chunks = new HashMap<>(); + for (CompletableFuture future : chunkLoadings) { + @Nullable + ChunkAccess chunk = future.getNow(null); + checkState(chunk != null, "Failed to generate a chunk, regen failed."); + chunks.put(chunk.getPos(), chunk); + } + + for (BlockVector3 vec : region) { + BlockPos pos = new BlockPos(vec.x(), vec.y(), vec.z()); + ChunkAccess chunk = chunks.get(new ChunkPos(pos)); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(pos); + int internalId = Block.getId(blockData); + BlockStateHolder state = BlockStateIdAccess.getBlockStateById(internalId); + Objects.requireNonNull(state); + BlockEntity blockEntity = chunk.getBlockEntity(pos); + if (blockEntity != null) { + net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(serverWorld.registryAccess()); + state = state.toBaseBlock(LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag))); + } + extent.setBlock(vec, state.toBaseBlock()); + if (options.shouldRegenBiomes()) { + Biome origBiome = chunk.getNoiseBiome(vec.x(), vec.y(), vec.z()).value(); + BiomeType adaptedBiome = adapt(serverWorld, origBiome); + if (adaptedBiome != null) { + extent.setBiome(vec, adaptedBiome); + } + } + } + } + + @SuppressWarnings("unchecked") + private List> submitChunkLoadTasks(Region region, ServerLevel serverWorld) { + ServerChunkCache chunkManager = serverWorld.getChunkSource(); + List> chunkLoadings = new ArrayList<>(); + // Pre-gen all the chunks + for (BlockVector2 chunk : region.getChunks()) { + try { + //noinspection unchecked + chunkLoadings.add( + ((CompletableFuture>) + getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) + .thenApply(either -> either.orElse(null)) + ); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException("Couldn't load chunk for regen.", e); + } + } + return chunkLoadings; + } + + private ResourceKey getWorldDimKey(Environment env) { + switch (env) { + case NETHER: + return LevelStem.NETHER; + case THE_END: + return LevelStem.END; + case NORMAL: + default: + return LevelStem.OVERWORLD; + } + } + + private static final Set SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( + SideEffect.NEIGHBORS, + SideEffect.LIGHTING, + SideEffect.VALIDATION, + SideEffect.ENTITY_AI, + SideEffect.EVENTS, + SideEffect.UPDATE + ); + + @Override + public Set getSupportedSideEffects() { + return SUPPORTED_SIDE_EFFECTS; + } + + @Override + public boolean clearContainerBlockContents(World world, BlockVector3 pt) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + + BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z())); + if (entity instanceof Clearable) { + ((Clearable) entity).clearContent(); + return true; + } + return false; + } + + @Override + public void initializeRegistries() { + DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer(); + // Biomes + for (ResourceLocation name : server.registryAccess().lookupOrThrow(Registries.BIOME).keySet()) { + if (BiomeType.REGISTRY.get(name.toString()) == null) { + BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString())); + } + } + + // BiomeCategories + Registry biomeRegistry = server.registryAccess().lookupOrThrow(Registries.BIOME); + biomeRegistry.getTags().forEach(tag -> { + String key = tag.key().location().toString(); + if (BiomeCategory.REGISTRY.get(key) == null) { + BiomeCategory.REGISTRY.register(key, new BiomeCategory( + key, + () -> biomeRegistry.get(tag.key()) + .stream() + .flatMap(HolderSet.Named::stream) + .map(Holder::value) + .map(this::adapt) + .collect(Collectors.toSet())) + ); + } + }); + } + + @Override + public void sendBiomeUpdates(World world, Iterable chunks) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + + List nativeChunks = chunks instanceof Collection chunkCollection ? Lists.newArrayListWithCapacity(chunkCollection.size()) : Lists.newArrayList(); + for (BlockVector2 chunk : chunks) { + nativeChunks.add(originalWorld.getChunk(chunk.x(), chunk.z(), ChunkStatus.BIOMES, false)); + } + originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks); + } + + // ------------------------------------------------------------------------ + // Code that is less likely to break + // ------------------------------------------------------------------------ + + /** + * Converts from a non-native NMS NBT structure to a native WorldEdit NBT + * structure. + * + * @param foreign non-native NMS NBT structure + * @return native WorldEdit NBT structure + */ + @Override + public LinTag toNativeLin(net.minecraft.nbt.Tag foreign) { + if (foreign == null) { + return null; + } + if (foreign instanceof net.minecraft.nbt.CompoundTag) { + Map> values = new HashMap<>(); + Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); + + for (String str : foreignKeys) { + net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); + values.put(str, toNativeLin(base)); + } + return LinCompoundTag.of(values); + } else if (foreign instanceof net.minecraft.nbt.ByteTag) { + return LinByteTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); + } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { + return LinByteArrayTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); + } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { + return LinDoubleTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); + } else if (foreign instanceof net.minecraft.nbt.FloatTag) { + return LinFloatTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); + } else if (foreign instanceof net.minecraft.nbt.IntTag) { + return LinIntTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); + } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { + return LinIntArrayTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); + } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { + return LinLongArrayTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); + } else if (foreign instanceof net.minecraft.nbt.ListTag) { + try { + return toNativeLinList((net.minecraft.nbt.ListTag) foreign); + } catch (Throwable e) { + logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); + } + } else if (foreign instanceof net.minecraft.nbt.LongTag) { + return LinLongTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); + } else if (foreign instanceof net.minecraft.nbt.ShortTag) { + return LinShortTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); + } else if (foreign instanceof net.minecraft.nbt.StringTag) { + return LinStringTag.of(foreign.getAsString()); + } else if (foreign instanceof net.minecraft.nbt.EndTag) { + return LinEndTag.instance(); + } + throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); + } + + /** + * Convert a foreign NBT list tag into a native WorldEdit one. + * + * @param foreign the foreign tag + * @return the converted tag + * @throws SecurityException on error + * @throws IllegalArgumentException on error + */ + private LinListTag toNativeLinList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { + LinListTag.Builder> builder = LinListTag.builder( + LinTagType.fromId(LinTagId.fromId(foreign.getElementType())) + ); + + for (net.minecraft.nbt.Tag tag : foreign) { + builder.add(toNativeLin(tag)); + } + + return builder.build(); + } + + /** + * Converts a WorldEdit-native NBT structure to a NMS structure. + * + * @param foreign structure to convert + * @return non-native structure + */ + @Override + public net.minecraft.nbt.Tag fromNativeLin(LinTag foreign) { + if (foreign == null) { + return null; + } + if (foreign instanceof LinCompoundTag compoundTag) { + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + for (var entry : compoundTag.value().entrySet()) { + tag.put(entry.getKey(), fromNativeLin(entry.getValue())); + } + return tag; + } else if (foreign instanceof LinByteTag byteTag) { + return net.minecraft.nbt.ByteTag.valueOf(byteTag.valueAsByte()); + } else if (foreign instanceof LinByteArrayTag byteArrayTag) { + return new net.minecraft.nbt.ByteArrayTag(byteArrayTag.value()); + } else if (foreign instanceof LinDoubleTag doubleTag) { + return net.minecraft.nbt.DoubleTag.valueOf(doubleTag.valueAsDouble()); + } else if (foreign instanceof LinFloatTag floatTag) { + return net.minecraft.nbt.FloatTag.valueOf(floatTag.valueAsFloat()); + } else if (foreign instanceof LinIntTag intTag) { + return net.minecraft.nbt.IntTag.valueOf(intTag.valueAsInt()); + } else if (foreign instanceof LinIntArrayTag intArrayTag) { + return new net.minecraft.nbt.IntArrayTag(intArrayTag.value()); + } else if (foreign instanceof LinLongArrayTag longArrayTag) { + return new net.minecraft.nbt.LongArrayTag(longArrayTag.value()); + } else if (foreign instanceof LinListTag listTag) { + net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); + for (var t : listTag.value()) { + tag.add(fromNativeLin(t)); + } + return tag; + } else if (foreign instanceof LinLongTag longTag) { + return net.minecraft.nbt.LongTag.valueOf(longTag.valueAsLong()); + } else if (foreign instanceof LinShortTag shortTag) { + return net.minecraft.nbt.ShortTag.valueOf(shortTag.valueAsShort()); + } else if (foreign instanceof LinStringTag stringTag) { + return net.minecraft.nbt.StringTag.valueOf(stringTag.value()); + } else if (foreign instanceof LinEndTag) { + return net.minecraft.nbt.EndTag.INSTANCE; + } else { + throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); + } + } + + @Override + public boolean supportsWatchdog() { + return watchdog != null; + } + + @Override + public void tickWatchdog() { + watchdog.tick(); + } + + private class SpigotWatchdog implements Watchdog { + private final Field instanceField; + private final Field lastTickField; + + SpigotWatchdog() throws NoSuchFieldException { + Field instanceField = WatchdogThread.class.getDeclaredField("instance"); + instanceField.setAccessible(true); + this.instanceField = instanceField; + + Field lastTickField = WatchdogThread.class.getDeclaredField("lastTick"); + lastTickField.setAccessible(true); + this.lastTickField = lastTickField; + } + + @Override + public void tick() { + try { + WatchdogThread instance = (WatchdogThread) this.instanceField.get(null); + if ((long) lastTickField.get(instance) != 0) { + WatchdogThread.tick(); + } + } catch (IllegalAccessException e) { + logger.log(Level.WARNING, "Failed to tick watchdog", e); + } + } + } + + private static class MojangWatchdog implements Watchdog { + private final DedicatedServer server; + private final Field tickField; + + MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { + this.server = server; + Field tickField = MinecraftServer.class.getDeclaredField(StaticRefraction.NEXT_TICK_TIME); + if (tickField.getType() != long.class) { + throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); + } + tickField.setAccessible(true); + this.tickField = tickField; + } + + @Override + public void tick() { + try { + tickField.set(server, Util.getMillis()); + } catch (IllegalAccessException ignored) { + } + } + } + + private static class NoOpWorldLoadListener implements ChunkProgressListener { + @Override + public void updateSpawnPos(ChunkPos spawnPos) { + } + + @Override + public void onStatusChange(ChunkPos pos, @org.jetbrains.annotations.Nullable ChunkStatus status) { + } + + @Override + public void start() { + } + + @Override + public void stop() { + } + + } +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightDataConverters.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightDataConverters.java new file mode 100644 index 000000000..0bcefa714 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightDataConverters.java @@ -0,0 +1,2795 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_3; + +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.schemas.Schema; +import com.mojang.serialization.Dynamic; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.FloatTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.GsonHelper; +import net.minecraft.util.StringUtil; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.world.item.DyeColor; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinCompoundTag; + +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.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({ "rawtypes", "unchecked" }) +class PaperweightDataConverters 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((LinCompoundTag) original, srcVer); + } else if (type == FixTypes.BLOCK_ENTITY) { + return (T) fixBlockEntity((LinCompoundTag) original, srcVer); + } else if (type == FixTypes.ENTITY) { + return (T) fixEntity((LinCompoundTag) 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 LinCompoundTag fixChunk(LinCompoundTag originalChunk, int srcVer) { + CompoundTag tag = (CompoundTag) adapter.fromNativeLin(originalChunk); + CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); + return (LinCompoundTag) adapter.toNativeLin(fixed); + } + + private LinCompoundTag fixBlockEntity(LinCompoundTag origTileEnt, int srcVer) { + CompoundTag tag = (CompoundTag) adapter.fromNativeLin(origTileEnt); + CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); + return (LinCompoundTag) adapter.toNativeLin(fixed); + } + + private LinCompoundTag fixEntity(LinCompoundTag origEnt, int srcVer) { + CompoundTag tag = (CompoundTag) adapter.fromNativeLin(origEnt); + CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); + return (LinCompoundTag) adapter.toNativeLin(fixed); + } + + private String fixBlockState(String blockState, int srcVer) { + CompoundTag stateNBT = stateToNBT(blockState); + Dynamic dynamic = new Dynamic<>(OPS_NBT, stateNBT); + CompoundTag fixed = (CompoundTag) INSTANCE.fixer.update(References.BLOCK_STATE, dynamic, srcVer, DATA_VERSION).getValue(); + return nbtToState(fixed); + } + + private String nbtToState(CompoundTag tagCompound) { + StringBuilder sb = new StringBuilder(); + sb.append(tagCompound.getString("Name")); + if (tagCompound.contains("Properties", 10)) { + sb.append('['); + CompoundTag props = tagCompound.getCompound("Properties"); + sb.append(props.getAllKeys().stream().map(k -> k + "=" + props.getString(k).replace("\"", "")).collect(Collectors.joining(","))); + sb.append(']'); + } + return sb.toString(); + } + + private static CompoundTag stateToNBT(String blockState) { + int propIdx = blockState.indexOf('['); + CompoundTag tag = new CompoundTag(); + if (propIdx < 0) { + tag.putString("Name", blockState); + } else { + tag.putString("Name", blockState.substring(0, propIdx)); + CompoundTag propTag = new 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, References.BIOME); + } + + private String fixItemType(String key, int srcVer) { + return fixName(key, srcVer, References.ITEM_NAME); + } + + private static String fixName(String key, int srcVer, TypeReference type) { + return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, StringTag.valueOf(key)), srcVer, DATA_VERSION) + .getValue().getAsString(); + } + + private final PaperweightAdapter adapter; + + private static final NbtOps OPS_NBT = NbtOps.INSTANCE; + private static final int LEGACY_VERSION = 1343; + private static int DATA_VERSION; + static PaperweightDataConverters 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(References.LEVEL), + PLAYER(References.PLAYER), + CHUNK(References.CHUNK), + BLOCK_ENTITY(References.BLOCK_ENTITY), + ENTITY(References.ENTITY), + ITEM_INSTANCE(References.ITEM_STACK), + OPTIONS(References.OPTIONS), + STRUCTURE(References.STRUCTURE); + + private final TypeReference type; + + LegacyType(TypeReference type) { + this.type = type; + DFU_TO_LEGACY.put(type.typeName(), this); + } + + public TypeReference getDFUType() { + return type; + } + } + + PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { + DATA_VERSION = dataVersion; + INSTANCE = this; + this.adapter = adapter; + registerConverters(); + registerInspectors(); + this.fixer = new WrappedDataFixer(DataFixers.getDataFixer()); + } + + @SuppressWarnings("unchecked") + 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) { + CompoundTag cmp = (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 CompoundTag convert(LegacyType type, CompoundTag cmp, int sourceVer, int desiredVersion) { + List converters = PaperweightDataConverters.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 = PaperweightDataConverters.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 CompoundTag convert(LegacyType type, CompoundTag cmp) { + return convert(type.getDFUType(), cmp); + } + + public static CompoundTag convert(LegacyType type, CompoundTag cmp, int sourceVer) { + return convert(type.getDFUType(), cmp, sourceVer); + } + + public static CompoundTag convert(LegacyType type, CompoundTag cmp, int sourceVer, int targetVer) { + return convert(type.getDFUType(), cmp, sourceVer, targetVer); + } + + public static CompoundTag convert(TypeReference type, CompoundTag cmp) { + int i = cmp.contains("DataVersion", 99) ? cmp.getInt("DataVersion") : -1; + return convert(type, cmp, i); + } + + public static CompoundTag convert(TypeReference type, CompoundTag cmp, int sourceVer) { + return convert(type, cmp, sourceVer, DATA_VERSION); + } + + public static CompoundTag convert(TypeReference type, CompoundTag cmp, int sourceVer, int targetVer) { + if (sourceVer >= targetVer) { + return cmp; + } + return (CompoundTag) INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, cmp), sourceVer, targetVer).getValue(); + } + + + public interface DataInspector { + CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer); + } + + public interface DataConverter { + + int getDataVersion(); + + CompoundTag convert(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", ResourceLocation.parse("item")); + map.put("EntityExperienceOrb", ResourceLocation.parse("xp_orb")); + map.put("EntityAreaEffectCloud", ResourceLocation.parse("area_effect_cloud")); + map.put("EntityGuardianElder", ResourceLocation.parse("elder_guardian")); + map.put("EntitySkeletonWither", ResourceLocation.parse("wither_skeleton")); + map.put("EntitySkeletonStray", ResourceLocation.parse("stray")); + map.put("EntityEgg", ResourceLocation.parse("egg")); + map.put("EntityLeash", ResourceLocation.parse("leash_knot")); + map.put("EntityPainting", ResourceLocation.parse("painting")); + map.put("EntityTippedArrow", ResourceLocation.parse("arrow")); + map.put("EntitySnowball", ResourceLocation.parse("snowball")); + map.put("EntityLargeFireball", ResourceLocation.parse("fireball")); + map.put("EntitySmallFireball", ResourceLocation.parse("small_fireball")); + map.put("EntityEnderPearl", ResourceLocation.parse("ender_pearl")); + map.put("EntityEnderSignal", ResourceLocation.parse("eye_of_ender_signal")); + map.put("EntityPotion", ResourceLocation.parse("potion")); + map.put("EntityThrownExpBottle", ResourceLocation.parse("xp_bottle")); + map.put("EntityItemFrame", ResourceLocation.parse("item_frame")); + map.put("EntityWitherSkull", ResourceLocation.parse("wither_skull")); + map.put("EntityTNTPrimed", ResourceLocation.parse("tnt")); + map.put("EntityFallingBlock", ResourceLocation.parse("falling_block")); + map.put("EntityFireworks", ResourceLocation.parse("fireworks_rocket")); + map.put("EntityZombieHusk", ResourceLocation.parse("husk")); + map.put("EntitySpectralArrow", ResourceLocation.parse("spectral_arrow")); + map.put("EntityShulkerBullet", ResourceLocation.parse("shulker_bullet")); + map.put("EntityDragonFireball", ResourceLocation.parse("dragon_fireball")); + map.put("EntityZombieVillager", ResourceLocation.parse("zombie_villager")); + map.put("EntityHorseSkeleton", ResourceLocation.parse("skeleton_horse")); + map.put("EntityHorseZombie", ResourceLocation.parse("zombie_horse")); + map.put("EntityArmorStand", ResourceLocation.parse("armor_stand")); + map.put("EntityHorseDonkey", ResourceLocation.parse("donkey")); + map.put("EntityHorseMule", ResourceLocation.parse("mule")); + map.put("EntityEvokerFangs", ResourceLocation.parse("evocation_fangs")); + map.put("EntityEvoker", ResourceLocation.parse("evocation_illager")); + map.put("EntityVex", ResourceLocation.parse("vex")); + map.put("EntityVindicator", ResourceLocation.parse("vindication_illager")); + map.put("EntityIllagerIllusioner", ResourceLocation.parse("illusion_illager")); + map.put("EntityMinecartCommandBlock", ResourceLocation.parse("commandblock_minecart")); + map.put("EntityBoat", ResourceLocation.parse("boat")); + map.put("EntityMinecartRideable", ResourceLocation.parse("minecart")); + map.put("EntityMinecartChest", ResourceLocation.parse("chest_minecart")); + map.put("EntityMinecartFurnace", ResourceLocation.parse("furnace_minecart")); + map.put("EntityMinecartTNT", ResourceLocation.parse("tnt_minecart")); + map.put("EntityMinecartHopper", ResourceLocation.parse("hopper_minecart")); + map.put("EntityMinecartMobSpawner", ResourceLocation.parse("spawner_minecart")); + map.put("EntityCreeper", ResourceLocation.parse("creeper")); + map.put("EntitySkeleton", ResourceLocation.parse("skeleton")); + map.put("EntitySpider", ResourceLocation.parse("spider")); + map.put("EntityGiantZombie", ResourceLocation.parse("giant")); + map.put("EntityZombie", ResourceLocation.parse("zombie")); + map.put("EntitySlime", ResourceLocation.parse("slime")); + map.put("EntityGhast", ResourceLocation.parse("ghast")); + map.put("EntityPigZombie", ResourceLocation.parse("zombie_pigman")); + map.put("EntityEnderman", ResourceLocation.parse("enderman")); + map.put("EntityCaveSpider", ResourceLocation.parse("cave_spider")); + map.put("EntitySilverfish", ResourceLocation.parse("silverfish")); + map.put("EntityBlaze", ResourceLocation.parse("blaze")); + map.put("EntityMagmaCube", ResourceLocation.parse("magma_cube")); + map.put("EntityEnderDragon", ResourceLocation.parse("ender_dragon")); + map.put("EntityWither", ResourceLocation.parse("wither")); + map.put("EntityBat", ResourceLocation.parse("bat")); + map.put("EntityWitch", ResourceLocation.parse("witch")); + map.put("EntityEndermite", ResourceLocation.parse("endermite")); + map.put("EntityGuardian", ResourceLocation.parse("guardian")); + map.put("EntityShulker", ResourceLocation.parse("shulker")); + map.put("EntityPig", ResourceLocation.parse("pig")); + map.put("EntitySheep", ResourceLocation.parse("sheep")); + map.put("EntityCow", ResourceLocation.parse("cow")); + map.put("EntityChicken", ResourceLocation.parse("chicken")); + map.put("EntitySquid", ResourceLocation.parse("squid")); + map.put("EntityWolf", ResourceLocation.parse("wolf")); + map.put("EntityMushroomCow", ResourceLocation.parse("mooshroom")); + map.put("EntitySnowman", ResourceLocation.parse("snowman")); + map.put("EntityOcelot", ResourceLocation.parse("ocelot")); + map.put("EntityIronGolem", ResourceLocation.parse("villager_golem")); + map.put("EntityHorse", ResourceLocation.parse("horse")); + map.put("EntityRabbit", ResourceLocation.parse("rabbit")); + map.put("EntityPolarBear", ResourceLocation.parse("polar_bear")); + map.put("EntityLlama", ResourceLocation.parse("llama")); + map.put("EntityLlamaSpit", ResourceLocation.parse("llama_spit")); + map.put("EntityParrot", ResourceLocation.parse("parrot")); + map.put("EntityVillager", ResourceLocation.parse("villager")); + map.put("EntityEnderCrystal", ResourceLocation.parse("ender_crystal")); + map.put("TileEntityFurnace", ResourceLocation.parse("furnace")); + map.put("TileEntityChest", ResourceLocation.parse("chest")); + map.put("TileEntityEnderChest", ResourceLocation.parse("ender_chest")); + map.put("TileEntityRecordPlayer", ResourceLocation.parse("jukebox")); + map.put("TileEntityDispenser", ResourceLocation.parse("dispenser")); + map.put("TileEntityDropper", ResourceLocation.parse("dropper")); + map.put("TileEntitySign", ResourceLocation.parse("sign")); + map.put("TileEntityMobSpawner", ResourceLocation.parse("mob_spawner")); + map.put("TileEntityNote", ResourceLocation.parse("noteblock")); + map.put("TileEntityPiston", ResourceLocation.parse("piston")); + map.put("TileEntityBrewingStand", ResourceLocation.parse("brewing_stand")); + map.put("TileEntityEnchantTable", ResourceLocation.parse("enchanting_table")); + map.put("TileEntityEnderPortal", ResourceLocation.parse("end_portal")); + map.put("TileEntityBeacon", ResourceLocation.parse("beacon")); + map.put("TileEntitySkull", ResourceLocation.parse("skull")); + map.put("TileEntityLightDetector", ResourceLocation.parse("daylight_detector")); + map.put("TileEntityHopper", ResourceLocation.parse("hopper")); + map.put("TileEntityComparator", ResourceLocation.parse("comparator")); + map.put("TileEntityFlowerPot", ResourceLocation.parse("flower_pot")); + map.put("TileEntityBanner", ResourceLocation.parse("banner")); + map.put("TileEntityStructure", ResourceLocation.parse("structure_block")); + map.put("TileEntityEndGateway", ResourceLocation.parse("end_gateway")); + map.put("TileEntityCommand", ResourceLocation.parse("command_block")); + map.put("TileEntityShulkerBox", ResourceLocation.parse("shulker_box")); + map.put("TileEntityBed", ResourceLocation.parse("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, CompoundTag cmp, String key, int sourceVer, int targetVer) { + cmp.put(key, convert(type, cmp.getCompound(key), sourceVer, targetVer)); + } + + private static void convertItem(CompoundTag nbttagcompound, String key, int sourceVer, int targetVer) { + if (nbttagcompound.contains(key, 10)) { + convertCompound(LegacyType.ITEM_INSTANCE, nbttagcompound, key, sourceVer, targetVer); + } + } + + private static void convertItems(CompoundTag nbttagcompound, String key, int sourceVer, int targetVer) { + if (nbttagcompound.contains(key, 9)) { + ListTag nbttaglist = nbttagcompound.getList(key, 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set(j, convert(LegacyType.ITEM_INSTANCE, nbttaglist.getCompound(j), sourceVer, targetVer)); + } + } + + } + + private static class DataConverterEquipment implements DataConverter { + + DataConverterEquipment() { + } + + public int getDataVersion() { + return 100; + } + + public CompoundTag convert(CompoundTag cmp) { + ListTag nbttaglist = cmp.getList("Equipment", 10); + ListTag nbttaglist1; + + if (!nbttaglist.isEmpty() && !cmp.contains("HandItems", 10)) { + nbttaglist1 = new ListTag(); + nbttaglist1.add(nbttaglist.get(0)); + nbttaglist1.add(new CompoundTag()); + cmp.put("HandItems", nbttaglist1); + } + + if (nbttaglist.size() > 1 && !cmp.contains("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.contains("DropChances", 9)) { + nbttaglist1 = cmp.getList("DropChances", 5); + ListTag nbttaglist2; + + if (!cmp.contains("HandDropChances", 10)) { + nbttaglist2 = new ListTag(); + nbttaglist2.add(FloatTag.valueOf(nbttaglist1.getFloat(0))); + nbttaglist2.add(FloatTag.valueOf(0.0F)); + cmp.put("HandDropChances", nbttaglist2); + } + + if (!cmp.contains("ArmorDropChances", 10)) { + nbttaglist2 = new ListTag(); + nbttaglist2.add(FloatTag.valueOf(nbttaglist1.getFloat(1))); + nbttaglist2.add(FloatTag.valueOf(nbttaglist1.getFloat(2))); + nbttaglist2.add(FloatTag.valueOf(nbttaglist1.getFloat(3))); + nbttaglist2.add(FloatTag.valueOf(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 = ResourceLocation.parse(s).toString(); + if (i < 515 && DataInspectorBlockEntity.b.containsKey(key)) { + return DataInspectorBlockEntity.b.get(key); + } else { + return DataInspectorBlockEntity.c.get(key); + } + } + + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + if (!cmp.contains("tag", 10)) { + return cmp; + } else { + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + 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.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 { + + DataInspectorEntity() { + } + + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("EntityTag", 10)) { + 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; + + 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 CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + if (this.key.equals(ResourceLocation.parse(cmp.getString("id")))) { + cmp = this.inspectChecked(cmp, sourceVer, targetVer); + } + + return cmp; + } + + abstract CompoundTag inspectChecked(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; + } + + CompoundTag inspectChecked(CompoundTag nbttagcompound, int sourceVer, int targetVer) { + for (String s : this.keys) { + PaperweightDataConverters.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; + } + + CompoundTag inspectChecked(CompoundTag nbttagcompound, int sourceVer, int targetVer) { + for (String key : this.keys) { + PaperweightDataConverters.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 CompoundTag convert(CompoundTag 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"; + // Paper start + materials[409] = "minecraft:prismarine_shard"; + materials[410] = "minecraft:prismarine_crystals"; + materials[411] = "minecraft:rabbit"; + materials[412] = "minecraft:cooked_rabbit"; + materials[413] = "minecraft:rabbit_stew"; + materials[414] = "minecraft:rabbit_foot"; + materials[415] = "minecraft:rabbit_hide"; + materials[416] = "minecraft:armor_stand"; + materials[423] = "minecraft:mutton"; + materials[424] = "minecraft:cooked_mutton"; + materials[425] = "minecraft:banner"; + materials[426] = "minecraft:end_crystal"; + materials[427] = "minecraft:spruce_door"; + materials[428] = "minecraft:birch_door"; + materials[429] = "minecraft:jungle_door"; + materials[430] = "minecraft:acacia_door"; + materials[431] = "minecraft:dark_oak_door"; + materials[432] = "minecraft:chorus_fruit"; + materials[433] = "minecraft:chorus_fruit_popped"; + materials[434] = "minecraft:beetroot"; + materials[435] = "minecraft:beetroot_seeds"; + materials[436] = "minecraft:beetroot_soup"; + materials[437] = "minecraft:dragon_breath"; + materials[438] = "minecraft:splash_potion"; + materials[439] = "minecraft:spectral_arrow"; + materials[440] = "minecraft:tipped_arrow"; + materials[441] = "minecraft:lingering_potion"; + materials[442] = "minecraft:shield"; + materials[443] = "minecraft:elytra"; + materials[444] = "minecraft:spruce_boat"; + materials[445] = "minecraft:birch_boat"; + materials[446] = "minecraft:jungle_boat"; + materials[447] = "minecraft:acacia_boat"; + materials[448] = "minecraft:dark_oak_boat"; + materials[449] = "minecraft:totem_of_undying"; + materials[450] = "minecraft:shulker_shell"; + materials[452] = "minecraft:iron_nugget"; + materials[453] = "minecraft:knowledge_book"; + // Paper end + } + } + + private static class DataConverterArmorStand implements DataConverter { + + DataConverterArmorStand() { + } + + public int getDataVersion() { + return 147; + } + + public CompoundTag convert(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 CompoundTag convert(CompoundTag cmp) { + if ("minecraft:banner".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + + if (nbttagcompound2.contains("Base", 99)) { + cmp.putShort("Damage", (short) (nbttagcompound2.getShort("Base") & 15)); + if (nbttagcompound1.contains("display", 10)) { + CompoundTag nbttagcompound3 = nbttagcompound1.getCompound("display"); + + if (nbttagcompound3.contains("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 CompoundTag convert(CompoundTag cmp) { + if ("minecraft:potion".equals(cmp.getString("id"))) { + CompoundTag 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 CompoundTag convert(CompoundTag cmp) { + if ("minecraft:spawn_egg".equals(cmp.getString("id"))) { + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + CompoundTag 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("MinecartRideable", "MinecartChest", "MinecartFurnace", "MinecartTNT", "MinecartSpawner", "MinecartHopper", "MinecartCommandBlock"); + + DataConverterMinecart() { + } + + public int getDataVersion() { + return 106; + } + + public CompoundTag convert(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 CompoundTag convert(CompoundTag cmp) { + if (!"MobSpawner".equals(cmp.getString("id"))) { + return cmp; + } else { + if (cmp.contains("EntityId", 8)) { + String s = cmp.getString("EntityId"); + CompoundTag nbttagcompound1 = cmp.getCompound("SpawnData"); + + nbttagcompound1.putString("id", s.isEmpty() ? "Pig" : s); + cmp.put("SpawnData", nbttagcompound1); + cmp.remove("EntityId"); + } + + if (cmp.contains("SpawnPotentials", 9)) { + ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int i = 0; i < nbttaglist.size(); ++i) { + CompoundTag nbttagcompound2 = nbttaglist.getCompound(i); + + if (nbttagcompound2.contains("Type", 8)) { + 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 CompoundTag convert(CompoundTag cmp) { + if (cmp.contains("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 CompoundTag convert(CompoundTag 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 CompoundTag convert(CompoundTag cmp) { + if ("EntityHorse".equals(cmp.getString("id")) && !cmp.contains("SaddleItem", 10) && cmp.getBoolean("Saddle")) { + CompoundTag nbttagcompound1 = new 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 CompoundTag convert(CompoundTag 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.from2DDataValue(cmp.getByte("Direction")); + cmp.putInt("TileX", cmp.getInt("TileX") + enumdirection.getStepX()); + cmp.putInt("TileY", cmp.getInt("TileY") + enumdirection.getStepY()); + cmp.putInt("TileZ", cmp.getInt("TileZ") + enumdirection.getStepZ()); + cmp.remove("Direction"); + if (flag1 && cmp.contains("ItemRotation", 99)) { + cmp.putByte("ItemRotation", (byte) (cmp.getByte("ItemRotation") * 2)); + } + } else { + enumdirection = Direction.from2DDataValue(cmp.getByte("Dir")); + cmp.remove("Dir"); + } + + cmp.putByte("Facing", (byte) enumdirection.get2DDataValue()); + } + + return cmp; + } + } + + private static class DataConverterDropChances implements DataConverter { + + DataConverterDropChances() { + } + + public int getDataVersion() { + return 113; + } + + public CompoundTag convert(CompoundTag cmp) { + ListTag 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 CompoundTag convert(CompoundTag cmp) { + while (cmp.contains("Riding", 10)) { + CompoundTag nbttagcompound1 = this.b(cmp); + + this.convert(cmp, nbttagcompound1); + cmp = nbttagcompound1; + } + + return cmp; + } + + protected void convert(CompoundTag nbttagcompound, CompoundTag nbttagcompound1) { + ListTag nbttaglist = new ListTag(); + + nbttaglist.add(nbttagcompound); + nbttagcompound1.put("Passengers", nbttaglist); + } + + protected CompoundTag b(CompoundTag nbttagcompound) { + CompoundTag nbttagcompound1 = nbttagcompound.getCompound("Riding"); + + nbttagcompound.remove("Riding"); + return nbttagcompound1; + } + } + + private static class DataConverterBook implements DataConverter { + + DataConverterBook() { + } + + public int getDataVersion() { + return 165; + } + + public CompoundTag convert(CompoundTag cmp) { + if ("minecraft:written_book".equals(cmp.getString("id"))) { + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("pages", 9)) { + ListTag nbttaglist = nbttagcompound1.getList("pages", 8); + + for (int i = 0; i < nbttaglist.size(); ++i) { + String s = nbttaglist.getString(i); + Component object = null; + + if (!"null".equals(s) && !StringUtil.isNullOrEmpty(s)) { + if ((s.charAt(0) != 34 || s.charAt(s.length() - 1) != 34) && (s.charAt(0) != 123 || s.charAt(s.length() - 1) != 125)) { + object = Component.literal(s); + } else { + try { + object = GsonHelper.fromJson(DataConverterSignText.a, s, Component.class, true); + if (object == null) { + object = Component.literal(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = Component.Serializer.fromJson(s, MinecraftServer.getServer().registryAccess()); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = Component.Serializer.fromJsonLenient(s, MinecraftServer.getServer().registryAccess()); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = Component.literal(s); + } + } + } else { + object = Component.literal(""); + } + + nbttaglist.set(i, StringTag.valueOf(Component.Serializer.toJson(object, MinecraftServer.getServer().registryAccess()))); + } + + nbttagcompound1.put("pages", nbttaglist); + } + } + + return cmp; + } + } + + private static class DataConverterCookedFish implements DataConverter { + + private static final ResourceLocation a = ResourceLocation.parse("cooked_fished"); + + DataConverterCookedFish() { + } + + public int getDataVersion() { + return 502; + } + + public CompoundTag convert(CompoundTag cmp) { + if (cmp.contains("id", 8) && DataConverterCookedFish.a.equals(ResourceLocation.parse(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 CompoundTag convert(CompoundTag 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 CompoundTag convert(CompoundTag cmp) { + cmp.putString("useVbo", "true"); + return cmp; + } + } + + private static class DataConverterGuardian implements DataConverter { + + DataConverterGuardian() { + } + + public int getDataVersion() { + return 700; + } + + public CompoundTag convert(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 CompoundTag convert(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 CompoundTag convert(CompoundTag cmp) { + if ("Zombie".equals(cmp.getString("id"))) { + int i = cmp.getInt("ZombieType"); + + switch (i) { + case 0: + default: + break; + + 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"); + } + + cmp.remove("ZombieType"); + } + + return cmp; + } + } + + private static class DataConverterHorse implements DataConverter { + + DataConverterHorse() { + } + + public int getDataVersion() { + return 703; + } + + public CompoundTag convert(CompoundTag cmp) { + if ("EntityHorse".equals(cmp.getString("id"))) { + int i = cmp.getInt("Type"); + + switch (i) { + case 0: + default: + cmp.putString("id", "Horse"); + break; + + 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"); + } + + 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 CompoundTag convert(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 CompoundTag convert(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 CompoundTag convert(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)) { + CompoundTag 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 CompoundTag convert(CompoundTag 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 CompoundTag convert(CompoundTag cmp) { + if ("minecraft:shulker_box".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + 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 CompoundTag convert(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 CompoundTag convert(CompoundTag 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 CompoundTag convert(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(PaperweightDataConverters.class); + + DataConverterBedBlock() { + } + + public int getDataVersion() { + return 1125; + } + + public CompoundTag convert(CompoundTag cmp) { + try { + 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) { + CompoundTag 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; + CompoundTag nbttagcompound3 = new 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 CompoundTag convert(CompoundTag cmp) { + if ("minecraft:bed".equals(cmp.getString("id")) && cmp.getShort("Damage") == 0) { + cmp.putShort("Damage", (short) DyeColor.RED.getId()); + } + + return cmp; + } + } + + private static class DataConverterSignText implements DataConverter { + + public static final Gson a = new GsonBuilder().registerTypeAdapter(Component.class, new JsonDeserializer() { + MutableComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { + if (jsonelement.isJsonPrimitive()) { + return Component.literal(jsonelement.getAsString()); + } else if (jsonelement.isJsonArray()) { + JsonArray jsonarray = jsonelement.getAsJsonArray(); + MutableComponent ichatbasecomponent = null; + Iterator iterator = jsonarray.iterator(); + + while (iterator.hasNext()) { + JsonElement jsonelement1 = (JsonElement) iterator.next(); + MutableComponent ichatbasecomponent1 = this.a(jsonelement1, jsonelement1.getClass(), jsondeserializationcontext); + + if (ichatbasecomponent == null) { + ichatbasecomponent = ichatbasecomponent1; + } else { + ichatbasecomponent.append(ichatbasecomponent1); + } + } + + return ichatbasecomponent; + } 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 CompoundTag convert(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(CompoundTag nbttagcompound, String s) { + String s1 = nbttagcompound.getString(s); + Component object = null; + + if (!"null".equals(s1) && !StringUtil.isNullOrEmpty(s1)) { + if ((s1.charAt(0) != 34 || s1.charAt(s1.length() - 1) != 34) && (s1.charAt(0) != 123 || s1.charAt(s1.length() - 1) != 125)) { + object = Component.literal(s1); + } else { + try { + object = GsonHelper.fromJson(DataConverterSignText.a, s1, Component.class, true); + if (object == null) { + object = Component.literal(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = Component.Serializer.fromJson(s1, MinecraftServer.getServer().registryAccess()); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = Component.Serializer.fromJsonLenient(s1, MinecraftServer.getServer().registryAccess()); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = Component.literal(s1); + } + } + } else { + object = Component.literal(""); + } + + nbttagcompound.putString(s, Component.Serializer.toJson(object, MinecraftServer.getServer().registryAccess())); + } + } + + private static class DataInspectorPlayerVehicle implements DataInspector { + @Override + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.contains("RootVehicle", 10)) { + CompoundTag 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 CompoundTag inspect(CompoundTag 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 CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + ListTag nbttaglist; + int j; + CompoundTag nbttagcompound1; + + if (cmp.contains("entities", 9)) { + nbttaglist = cmp.getList("entities", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttagcompound1 = (CompoundTag) 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 = (CompoundTag) 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 CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.contains("Level", 10)) { + CompoundTag nbttagcompound1 = cmp.getCompound("Level"); + ListTag 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, (CompoundTag) 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, (CompoundTag) nbttaglist.get(j), sourceVer, targetVer)); + } + } + } + + return cmp; + } + } + + private static class DataInspectorEntityPassengers implements DataInspector { + @Override + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.contains("Passengers", 9)) { + ListTag 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 CompoundTag inspect(CompoundTag 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 CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + if (entityVillager.equals(ResourceLocation.parse(cmp.getString("id"))) && cmp.contains("Offers", 10)) { + CompoundTag nbttagcompound1 = cmp.getCompound("Offers"); + + if (nbttagcompound1.contains("Recipes", 9)) { + ListTag nbttaglist = nbttagcompound1.getList("Recipes", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + CompoundTag 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 CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + String s = cmp.getString("id"); + if (entityMinecartMobSpawner.equals(ResourceLocation.parse(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 CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + if (tileEntityMobSpawner.equals(ResourceLocation.parse(cmp.getString("id")))) { + if (cmp.contains("SpawnPotentials", 9)) { + ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + CompoundTag 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 CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + if (tileEntityCommand.equals(ResourceLocation.parse(cmp.getString("id")))) { + cmp.putString("id", "Control"); + convert(LegacyType.BLOCK_ENTITY, cmp, sourceVer, targetVer); + cmp.putString("id", "MinecartCommandBlock"); + } + + return cmp; + } + } +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightFakePlayer.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightFakePlayer.java new file mode 100644 index 000000000..140daa63b --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightFakePlayer.java @@ -0,0 +1,87 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_3; + +import com.mojang.authlib.GameProfile; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ParticleStatus; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.stats.Stat; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.player.ChatVisiblity; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.phys.Vec3; + +import java.util.OptionalInt; +import java.util.UUID; + +class PaperweightFakePlayer extends ServerPlayer { + private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]"); + private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D); + private static final ClientInformation FAKE_CLIENT_INFO = new ClientInformation( + "en_US", 16, ChatVisiblity.FULL, true, 0, HumanoidArm.LEFT, false, false, ParticleStatus.ALL + ); + + PaperweightFakePlayer(ServerLevel world) { + super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE, FAKE_CLIENT_INFO); + } + + @Override + public Vec3 position() { + return ORIGIN; + } + + @Override + public void tick() { + } + + @Override + public void die(DamageSource damagesource) { + } + + @Override + public OptionalInt openMenu(MenuProvider factory) { + return OptionalInt.empty(); + } + + @Override + public void updateOptions(ClientInformation clientOptions) { + } + + @Override + public void displayClientMessage(Component message, boolean actionBar) { + } + + @Override + public void awardStat(Stat stat, int amount) { + } + + @Override + public void awardStat(Stat stat) { + } + + @Override + public void openTextEdit(SignBlockEntity sign, boolean front) { + } +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightWorldNativeAccess.java new file mode 100644 index 000000000..86d3fb598 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightWorldNativeAccess.java @@ -0,0 +1,192 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_3; + +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.world.block.BlockState; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.Tag; +import net.minecraft.server.level.FullChunkStatus; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.redstone.ExperimentalRedstoneUtils; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.event.block.BlockPhysicsEvent; +import org.enginehub.linbus.tree.LinCompoundTag; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.util.Objects; + +public class PaperweightWorldNativeAccess implements WorldNativeAccess { + private static final int UPDATE = 1; + private static final int NOTIFY = 2; + + private final PaperweightAdapter adapter; + private final WeakReference world; + private SideEffectSet sideEffectSet; + + public PaperweightWorldNativeAccess(PaperweightAdapter adapter, WeakReference world) { + this.adapter = adapter; + this.world = world; + } + + private ServerLevel getWorld() { + return Objects.requireNonNull(world.get(), "The reference to the world was lost"); + } + + @Override + public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + @Override + public LevelChunk getChunk(int x, int z) { + return getWorld().getChunk(x, z); + } + + @Override + public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) { + int stateId = BlockStateIdAccess.getBlockStateId(state); + return BlockStateIdAccess.isValidInternalId(stateId) + ? Block.stateById(stateId) + : ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); + } + + @Override + public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk chunk, BlockPos position) { + return chunk.getBlockState(position); + } + + @Nullable + @Override + public net.minecraft.world.level.block.state.BlockState setBlockState(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState state) { + return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE)); + } + + @Override + public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(net.minecraft.world.level.block.state.BlockState block, BlockPos position) { + return Block.updateFromNeighbourShapes(block, getWorld(), position); + } + + @Override + public BlockPos getPosition(int x, int y, int z) { + return new BlockPos(x, y, z); + } + + @Override + public void updateLightingForBlock(BlockPos position) { + getWorld().getChunkSource().getLightEngine().checkBlock(position); + } + + @Override + public boolean updateTileEntity(BlockPos position, LinCompoundTag tag) { + // We will assume that the tile entity was created for us + BlockEntity tileEntity = getWorld().getBlockEntity(position); + if (tileEntity == null) { + return false; + } + Tag nativeTag = adapter.fromNativeLin(tag); + PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity); + return true; + } + + @Override + public void notifyBlockUpdate(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { + if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { + getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY); + } + } + + @Override + public boolean isChunkTicking(LevelChunk chunk) { + return chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING); + } + + @Override + public void markBlockChanged(LevelChunk chunk, BlockPos position) { + if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { + getWorld().getChunkSource().blockChanged(position); + } + } + + @Override + public void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { + ServerLevel world = getWorld(); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + world.updateNeighborsAt(pos, oldState.getBlock()); + } else { + // When we don't want events, manually run the physics without them. + Block block = oldState.getBlock(); + fireNeighborChanged(pos, world, block, pos.west()); + fireNeighborChanged(pos, world, block, pos.east()); + fireNeighborChanged(pos, world, block, pos.below()); + fireNeighborChanged(pos, world, block, pos.above()); + fireNeighborChanged(pos, world, block, pos.north()); + fireNeighborChanged(pos, world, block, pos.south()); + } + if (newState.hasAnalogOutputSignal()) { + world.updateNeighbourForOutputSignal(pos, newState.getBlock()); + } + } + + @Override + public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { + ServerLevel world = getWorld(); + newState.onPlace(world, pos, oldState, false); + } + + private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { + world.getBlockState(neighborPos).handleNeighborChanged(world, neighborPos, block, ExperimentalRedstoneUtils.initialOrientation(world, null, null), false); + } + + @Override + public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) { + ServerLevel world = getWorld(); + oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + CraftWorld craftWorld = world.getWorld(); + BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState)); + world.getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + } + newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit); + newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); + } + + @Override + public void onBlockStateChange(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { + getWorld().onBlockStateChange(pos, oldState, newState); + } + + @Override + public void flush() { + + } +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/StaticRefraction.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/StaticRefraction.java new file mode 100644 index 000000000..c701df1d4 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/StaticRefraction.java @@ -0,0 +1,84 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_3; + +import com.sk89q.worldedit.bukkit.adapter.Refraction; + +/** + * Dedicated class to map all names that we use. + * + *

    + * Overloads are split into multiple fields, as they CAN have different obfuscated names. + *

    + */ +public final class StaticRefraction { + public static final String GET_CHUNK_FUTURE_MAIN_THREAD = Refraction.pickName( + "getChunkFutureMainThread", "c" + ); + public static final String MAIN_THREAD_PROCESSOR = Refraction.pickName( + "mainThreadProcessor", "g" + ); + public static final String NEXT_TICK_TIME = Refraction.pickName("nextTickTime", "e"); + public static final String GET_BLOCK_STATE = Refraction.pickName("getBlockState", "a_"); + /** + * {@code addFreshEntityWithPassengers(Entity entity)}. + */ + public static final String ADD_FRESH_ENTITY_WITH_PASSENGERS_ENTITY = Refraction.pickName( + "addFreshEntityWithPassengers", "a_" + ); + /** + * {@code addFreshEntityWithPassengers(Entity entity, CreatureSpawnEvent.SpawnReason reason)}. + */ + public static final String ADD_FRESH_ENTITY_WITH_PASSENGERS_ENTITY_SPAWN_REASON = + Refraction.pickName("addFreshEntityWithPassengers", "a_"); + /** + * {@code addFreshEntity(Entity entity)}. + */ + public static final String ADD_FRESH_ENTITY = Refraction.pickName("addFreshEntity", "b"); + /** + * {@code getBlockEntity(BlockPos blockPos)}. + */ + public static final String GET_BLOCK_ENTITY = Refraction.pickName("getBlockEntity", "c_"); + /** + * {@code setBlock(BlockPos blockPos, BlockState blockState, int flags)}. + */ + public static final String SET_BLOCK = Refraction.pickName("setBlock", "a"); + /** + * {@code setBlock(BlockPos blockPos, BlockState blockState, int flags, int maxUpdateDepth)}. + */ + public static final String SET_BLOCK_MAX_UPDATE = Refraction.pickName("setBlock", "a"); + public static final String REMOVE_BLOCK = Refraction.pickName("removeBlock", "a"); + /** + * {@code destroyBlock(BlockPos blockPos, boolean drop)}. + */ + public static final String DESTROY_BLOCK = Refraction.pickName("destroyBlock", "b"); + /** + * {@code destroyBlock(BlockPos blockPos, boolean drop, Entity breakingEntity)}. + */ + public static final String DESTROY_BLOCK_BREAKING_ENTITY = Refraction.pickName( + "destroyBlock", "a" + ); + /** + * {@code destroyBlock(BlockPos blockPos, boolean drop, Entity breakingEntity, int maxUpdateDepth)}. + */ + public static final String DESTROY_BLOCK_BREAKING_ENTITY_MAX_UPDATE = Refraction.pickName( + "destroyBlock", "a" + ); +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightBlockMaterial.java new file mode 100644 index 000000000..f0358eb10 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightBlockMaterial.java @@ -0,0 +1,175 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_3; + +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.EmptyBlockGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.level.material.PushReaction; +import org.bukkit.craftbukkit.block.data.CraftBlockData; + +import javax.annotation.Nullable; + +public class PaperweightBlockMaterial implements BlockMaterial { + + private final Block block; + private final BlockState blockState; + private final CraftBlockData craftBlockData; + private final org.bukkit.Material craftMaterial; + private final int opacity; + private final FaweCompoundTag tile; + + public PaperweightBlockMaterial(Block block) { + this(block, block.defaultBlockState()); + } + + public PaperweightBlockMaterial(Block block, BlockState blockState) { + this.block = block; + this.blockState = blockState; + this.craftBlockData = CraftBlockData.fromData(blockState); + this.craftMaterial = craftBlockData.getMaterial(); + opacity = blockState.getLightBlock(); + BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity( + BlockPos.ZERO, + blockState + ); + tile = tileEntity == null + ? null + : PaperweightGetBlocks.NMS_TO_TILE.apply(tileEntity); + } + + public Block getBlock() { + return block; + } + + public BlockState getState() { + return blockState; + } + + public CraftBlockData getCraftBlockData() { + return craftBlockData; + } + + @Override + public boolean isAir() { + return blockState.isAir(); + } + + @Override + public boolean isFullCube() { + return craftMaterial.isOccluding(); + } + + @Override + public boolean isOpaque() { + return blockState.canOcclude(); + } + + @Override + public boolean isPowerSource() { + return blockState.isSignalSource(); + } + + @Override + public boolean isLiquid() { + return !blockState.getFluidState().is(Fluids.EMPTY); + } + + @Override + public boolean isSolid() { + return blockState.isSolidRender(); + } + + @Override + public float getHardness() { + return craftBlockData.getState().destroySpeed; + } + + @Override + public float getResistance() { + return block.getExplosionResistance(); + } + + @Override + public float getSlipperiness() { + return block.getFriction(); + } + + @Override + public int getLightValue() { + return blockState.getLightEmission(); + } + + @Override + public int getLightOpacity() { + return opacity; + } + + @Override + public boolean isFragileWhenPushed() { + return blockState.getPistonPushReaction() == PushReaction.DESTROY; + } + + @Override + public boolean isUnpushable() { + return blockState.getPistonPushReaction() == PushReaction.BLOCK; + } + + @Override + public boolean isTicksRandomly() { + return blockState.isRandomlyTicking(); + } + + @SuppressWarnings("deprecation") + @Override + public boolean isMovementBlocker() { + return blockState.blocksMotion(); + } + + @Override + public boolean isBurnable() { + return craftMaterial.isBurnable(); + } + + @Override + public boolean isToolRequired() { + // Removed in 1.16.1, this is not present in higher versions + return false; + } + + @Override + public boolean isReplacedDuringPlacement() { + return blockState.canBeReplaced(); + } + + @Override + public boolean isTranslucent() { + return !blockState.canOcclude(); + } + + @Override + public boolean hasContainer() { + return block instanceof EntityBlock; + } + + @Override + public boolean isTile() { + return block instanceof EntityBlock; + } + + @Override + public @Nullable FaweCompoundTag defaultTile() { + return tile; + } + + @Override + public int getMapColor() { + // rgb field + return block.defaultMapColor().col; + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightFaweAdapter.java new file mode 100644 index 000000000..40e6ead32 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightFaweAdapter.java @@ -0,0 +1,619 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_3; + +import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; +import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; +import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.entity.LazyBaseEntity; +import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; +import com.fastasyncworldedit.core.queue.IBatchProcessor; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; +import com.fastasyncworldedit.core.util.NbtUtils; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.mojang.serialization.Codec; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_3.PaperweightAdapter; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_3.regen.PaperweightRegen; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +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.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.world.RegenOptions; +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.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import io.papermc.lib.PaperLib; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.WritableRegistry; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.StringRepresentable; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.chunk.LevelChunk; +import org.apache.logging.log4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.World; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.bukkit.entity.Player; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.OptionalInt; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static net.minecraft.core.registries.Registries.BIOME; + +public final class PaperweightFaweAdapter extends FaweAdapter { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; + private static final Codec COMPONENTS_CODEC = DataComponentPatch.CODEC.optionalFieldOf( + "components", DataComponentPatch.EMPTY + ).codec(); + + static { + try { + CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE = ChunkHolder.class.getDeclaredMethod("wasAccessibleSinceLastSave"); + } catch (NoSuchMethodException ignored) { // may not be present in newer paper versions + } + } + + private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil(); + + public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { + super(new PaperweightAdapter()); + } + + public Function blockEntityToCompoundTag() { + return blockEntity -> FaweCompoundTag.of( + () -> (LinCompoundTag) toNativeLin(blockEntity.saveWithId(DedicatedServer.getServer().registryAccess())) + ); + } + + public static Property adaptProperty(net.minecraft.world.level.block.state.properties.Property property) { + return switch (property) { + case net.minecraft.world.level.block.state.properties.BooleanProperty booleanProperty -> + new BooleanProperty(booleanProperty.getName(), ImmutableList.copyOf(booleanProperty.getPossibleValues())); + case net.minecraft.world.level.block.state.properties.IntegerProperty integerProperty -> + new IntegerProperty(integerProperty.getName(), ImmutableList.copyOf(integerProperty.getPossibleValues())); + case net.minecraft.world.level.block.state.properties.EnumProperty enumProperty -> { + if (enumProperty.getValueClass() == net.minecraft.core.Direction.class) { + yield new DirectionalProperty(enumProperty.getName(), enumProperty.getPossibleValues().stream() + .map(StringRepresentable::getSerializedName) + .map(s -> s.toUpperCase(Locale.ROOT)) + .map(Direction::valueOf) + .toList() + ); + } + yield new EnumProperty(enumProperty.getName(), enumProperty.getPossibleValues().stream() + .map(StringRepresentable::getSerializedName).collect(Collectors.toCollection(ArrayList::new))); + } + default -> throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + property.getClass().getSimpleName()); + }; + } + + private static String getEntityId(Entity entity) { + return net.minecraft.world.entity.EntityType.getKey(entity.getType()).toString(); + } + + private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { + entity.save(compoundTag); + } + + @Override + public BukkitImplAdapter getParent() { + return parent; + } + + private synchronized boolean init() { + if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) { + return false; + } + ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size + ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size + for (int i = 0; i < ibdToStateOrdinal.length; i++) { + BlockState blockState = BlockTypesCache.states[i]; + PaperweightBlockMaterial material = (PaperweightBlockMaterial) blockState.getMaterial(); + int id = Block.BLOCK_STATE_REGISTRY.getId(material.getState()); + char ordinal = blockState.getOrdinalChar(); + ibdToStateOrdinal[id] = ordinal; + ordinalToIbdID[ordinal] = id; + } + Map>> properties = new HashMap<>(); + try { + for (Field field : BlockStateProperties.class.getDeclaredFields()) { + Object obj = field.get(null); + if (!(obj instanceof net.minecraft.world.level.block.state.properties.Property state)) { + continue; + } + Property property = adaptProperty(state); + properties.compute(property.getName().toLowerCase(Locale.ROOT), (k, v) -> { + if (v == null) { + v = new ArrayList<>(Collections.singletonList(property)); + } else { + v.add(property); + } + return v; + }); + } + } catch (IllegalAccessException e) { + LOGGER.error("failed to initialize block states", e); + } finally { + allBlockProperties = ImmutableMap.copyOf(properties); + } + initialised = true; + return true; + } + + @Override + public BlockMaterial getMaterial(BlockType blockType) { + Block block = getBlock(blockType); + return new PaperweightBlockMaterial(block); + } + + @Override + public synchronized BlockMaterial getMaterial(BlockState state) { + net.minecraft.world.level.block.state.BlockState blockState = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState(); + return new PaperweightBlockMaterial(blockState.getBlock(), blockState); + } + + public Block getBlock(BlockType blockType) { + return DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.BLOCK) + .getValue(ResourceLocation.fromNamespaceAndPath(blockType.getNamespace(), blockType.getResource())); + } + + @Deprecated + @Override + public BlockState getBlock(Location location) { + Preconditions.checkNotNull(location); + + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + final ServerLevel handle = getServerLevel(location.getWorld()); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); + BlockState state = adapt(blockData); + if (state == null) { + org.bukkit.block.Block bukkitBlock = location.getBlock(); + state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } + return state; + } + + @Override + public BaseBlock getFullBlock(final Location location) { + Preconditions.checkNotNull(location); + + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = getServerLevel(location.getWorld()); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); + BlockState state = adapt(blockData); + if (state == null) { + org.bukkit.block.Block bukkitBlock = location.getBlock(); + state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } + if (state.getBlockType().getMaterial().hasContainer()) { + + // Read the NBT data + BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); + if (blockEntity != null) { + net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()); + return state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); + } + } + + return state.toBaseBlock(); + } + + @Override + public Set getSupportedSideEffects() { + return SideEffectSet.defaults().getSideEffectsToApply(); + } + + @Override + public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); + } + + @Override + public BaseEntity getEntity(org.bukkit.entity.Entity entity) { + Preconditions.checkNotNull(entity); + + CraftEntity craftEntity = ((CraftEntity) entity); + Entity mcEntity = craftEntity.getHandle(); + + String id = getEntityId(mcEntity); + EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); + Supplier saveTag = () -> { + final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); + readEntityIntoTag(mcEntity, minecraftTag); + //add Id for AbstractChangeSet to work + final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag); + final Map> tags = NbtUtils.getLinCompoundTagValues(tag); + tags.put("Id", LinStringTag.of(id)); + return LinCompoundTag.of(tags); + }; + return new LazyBaseEntity(type, saveTag); + + } + + @Override + public Component getRichBlockName(BlockType blockType) { + return parent.getRichBlockName(blockType); + } + + @Override + public Component getRichItemName(ItemType itemType) { + return parent.getRichItemName(itemType); + } + + @Override + public Component getRichItemName(BaseItemStack itemStack) { + return parent.getRichItemName(itemStack); + } + + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); + net.minecraft.world.level.block.state.BlockState mcState = material.getCraftBlockData().getState(); + return OptionalInt.of(Block.BLOCK_STATE_REGISTRY.getId(mcState)); + } + + @Override + public BlockState adapt(BlockData blockData) { + CraftBlockData cbd = ((CraftBlockData) blockData); + net.minecraft.world.level.block.state.BlockState ibd = cbd.getState(); + return adapt(ibd); + } + + public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) { + return BlockTypesCache.states[adaptToChar(blockState)]; + } + + public char adaptToChar(net.minecraft.world.level.block.state.BlockState blockState) { + int id = Block.BLOCK_STATE_REGISTRY.getId(blockState); + if (initialised) { + return ibdToStateOrdinal[id]; + } + synchronized (this) { + if (initialised) { + return ibdToStateOrdinal[id]; + } + try { + init(); + return ibdToStateOrdinal[id]; + } catch (ArrayIndexOutOfBoundsException e1) { + LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!", + blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1 + ); + return BlockTypesCache.ReservedIDs.AIR; + } + } + } + + public char ibdIDToOrdinal(int id) { + if (initialised) { + return ibdToStateOrdinal[id]; + } + synchronized (this) { + if (initialised) { + return ibdToStateOrdinal[id]; + } + init(); + return ibdToStateOrdinal[id]; + } + } + + @Override + public char[] getIbdToStateOrdinal() { + if (initialised) { + return ibdToStateOrdinal; + } + synchronized (this) { + if (initialised) { + return ibdToStateOrdinal; + } + init(); + return ibdToStateOrdinal; + } + } + + public int ordinalToIbdID(char ordinal) { + if (initialised) { + return ordinalToIbdID[ordinal]; + } + synchronized (this) { + if (initialised) { + return ordinalToIbdID[ordinal]; + } + init(); + return ordinalToIbdID[ordinal]; + } + } + + @Override + public int[] getOrdinalToIbdID() { + if (initialised) { + return ordinalToIbdID; + } + synchronized (this) { + if (initialised) { + return ordinalToIbdID; + } + init(); + return ordinalToIbdID; + } + } + + @Override + public > BlockData adapt(B state) { + PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); + return material.getCraftBlockData(); + } + + @Override + public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { + ServerLevel nmsWorld = getServerLevel(world); + ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); + if (map != null && wasAccessibleSinceLastSave(map)) { + boolean flag = false; + // PlayerChunk.d players = map.players; + Stream stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag) + */ Stream.empty(); + + ServerPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle(); + stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer) + .forEach(entityPlayer -> { + synchronized (chunkPacket) { + ClientboundLevelChunkWithLightPacket nmsPacket = (ClientboundLevelChunkWithLightPacket) chunkPacket.getNativePacket(); + if (nmsPacket == null) { + nmsPacket = mapUtil.create(this, chunkPacket); + chunkPacket.setNativePacket(nmsPacket); + } + try { + FaweCache.INSTANCE.CHUNK_FLAG.get().set(true); + entityPlayer.connection.send(nmsPacket); + } finally { + FaweCache.INSTANCE.CHUNK_FLAG.get().set(false); + } + } + }); + } + } + + @Override + public Map> getProperties(BlockType blockType) { + return getParent().getProperties(blockType); + } + + @Override + public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) { + int internalId = BlockStateIdAccess.getBlockStateId(blockState); + net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); + return blockState1.hasPostProcess( + getServerLevel(world), + new BlockPos(blockVector3.x(), blockVector3.y(), blockVector3.z()) + ); + } + + @Override + public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { + final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess(); + ItemStack stack = new ItemStack( + registryAccess.lookupOrThrow(Registries.ITEM).getValueOrThrow(ResourceKey.create( + Registries.ITEM, ResourceLocation.parse(baseItemStack.getType().id()) + )), + baseItemStack.getAmount() + ); + final CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNativeLin(baseItemStack.getNbt()); + if (nbt != null) { + final DataComponentPatch patch = COMPONENTS_CODEC + .parse(registryAccess.createSerializationContext(NbtOps.INSTANCE), nbt) + .getOrThrow(); + stack.applyComponents(patch); + } + return CraftItemStack.asCraftMirror(stack); + } + + @Override + protected void preCaptureStates(final ServerLevel serverLevel) { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + } + + @Override + protected List getCapturedBlockStatesCopy(final ServerLevel serverLevel) { + return new ArrayList<>(serverLevel.capturedBlockStates.values()); + } + + @Override + protected void postCaptureBlockStates(final ServerLevel serverLevel) { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + + @Override + protected ServerLevel getServerLevel(final World world) { + return ((CraftWorld) world).getHandle(); + } + + @Override + public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { + final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess(); + final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); + final net.minecraft.nbt.Tag tag = COMPONENTS_CODEC.encodeStart( + registryAccess.createSerializationContext(NbtOps.INSTANCE), + nmsStack.getComponentsPatch() + ).getOrThrow(); + return new BaseItemStack( + BukkitAdapter.asItemType(itemStack.getType()), + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)), + itemStack.getAmount() + ); + } + + @Override + public Tag toNative(net.minecraft.nbt.Tag foreign) { + return parent.toNative(foreign); + } + + @Override + public net.minecraft.nbt.Tag fromNative(Tag foreign) { + return parent.fromNative(foreign); + } + + @Override + public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { + return new PaperweightRegen(bukkitWorld, region, target, options).regenerate(); + } + + @Override + public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { + return new PaperweightGetBlocks(world, chunkX, chunkZ); + } + + @Override + public int getInternalBiomeId(BiomeType biomeType) { + final Registry registry = MinecraftServer + .getServer() + .registryAccess() + .lookupOrThrow(BIOME); + ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.id()); + Biome biome = registry.getValue(resourceLocation); + return registry.getId(biome); + } + + @Override + public Iterable getRegisteredBiomes() { + WritableRegistry biomeRegistry = (WritableRegistry) ((CraftServer) Bukkit.getServer()) + .getServer() + .registryAccess() + .lookupOrThrow(BIOME); + List keys = biomeRegistry.stream() + .map(biomeRegistry::getKey).filter(Objects::nonNull).toList(); + List namespacedKeys = new ArrayList<>(); + for (ResourceLocation key : keys) { + try { + namespacedKeys.add(CraftNamespacedKey.fromMinecraft(key)); + } catch (IllegalArgumentException e) { + LOGGER.error("Error converting biome key {}", key.toString(), e); + } + } + return namespacedKeys; + } + + @Override + public RelighterFactory getRelighterFactory() { + if (PaperLib.isPaper()) { + return new PaperweightStarlightRelighterFactory(); + } else { + return new NMSRelighterFactory(); + } + } + + @Override + public Map>> getAllProperties() { + if (initialised) { + return allBlockProperties; + } + synchronized (this) { + if (initialised) { + return allBlockProperties; + } + init(); + return allBlockProperties; + } + } + + @Override + public IBatchProcessor getTickingPostProcessor() { + return new PaperweightPostProcessor(); + } + + private boolean wasAccessibleSinceLastSave(ChunkHolder holder) { + if (PaperLib.isPaper()) { // Papers new chunk system has no related replacement - therefor we assume true. + return true; + } + try { + return (boolean) CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE.invoke(holder); + } catch (IllegalAccessException | InvocationTargetException ignored) { + return false; + } + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightFaweWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightFaweWorldNativeAccess.java new file mode 100644 index 000000000..ab2e0a277 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightFaweWorldNativeAccess.java @@ -0,0 +1,294 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_3; + +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.math.IntPair; +import com.fastasyncworldedit.core.util.TaskManager; +import com.fastasyncworldedit.core.util.task.RunnableVal; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.world.block.BlockState; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.FullChunkStatus; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.redstone.ExperimentalRedstoneUtils; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.event.block.BlockPhysicsEvent; +import org.enginehub.linbus.tree.LinCompoundTag; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess { + + private static final int UPDATE = 1; + private static final int NOTIFY = 2; + private static final Direction[] NEIGHBOUR_ORDER = { + Direction.EAST, + Direction.WEST, + Direction.DOWN, + Direction.UP, + Direction.NORTH, + Direction.SOUTH + }; + private final PaperweightFaweAdapter paperweightFaweAdapter; + private final WeakReference level; + private final AtomicInteger lastTick; + private final Set cachedChanges = new HashSet<>(); + private final Set cachedChunksToSend = new HashSet<>(); + private SideEffectSet sideEffectSet; + + public PaperweightFaweWorldNativeAccess(PaperweightFaweAdapter paperweightFaweAdapter, WeakReference level) { + this.paperweightFaweAdapter = paperweightFaweAdapter; + this.level = level; + // Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging. + // - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway. + this.lastTick = new AtomicInteger(MinecraftServer.currentTick); + } + + private Level getLevel() { + return Objects.requireNonNull(level.get(), "The reference to the world was lost"); + } + + @Override + public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + @Override + public LevelChunk getChunk(int x, int z) { + return getLevel().getChunk(x, z); + } + + @Override + public net.minecraft.world.level.block.state.BlockState toNative(BlockState blockState) { + int stateId = paperweightFaweAdapter.ordinalToIbdID(blockState.getOrdinalChar()); + return BlockStateIdAccess.isValidInternalId(stateId) + ? Block.stateById(stateId) + : ((CraftBlockData) BukkitAdapter.adapt(blockState)).getState(); + } + + @Override + public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk levelChunk, BlockPos blockPos) { + return levelChunk.getBlockState(blockPos); + } + + @Nullable + @Override + public synchronized net.minecraft.world.level.block.state.BlockState setBlockState( + LevelChunk levelChunk, BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState blockState + ) { + int currentTick = MinecraftServer.currentTick; + if (Fawe.isMainThread()) { + return levelChunk.setBlockState(blockPos, blockState, + this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE) + ); + } + // Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( ) + cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState)); + cachedChunksToSend.add(new IntPair(levelChunk.locX, levelChunk.locZ)); + boolean nextTick = lastTick.get() > currentTick; + if (nextTick || cachedChanges.size() >= 1024) { + if (nextTick) { + lastTick.set(currentTick); + } + flushAsync(nextTick); + } + return blockState; + } + + @Override + public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition( + net.minecraft.world.level.block.state.BlockState blockState, + BlockPos blockPos + ) { + return Block.updateFromNeighbourShapes(blockState, getLevel(), blockPos); + } + + @Override + public BlockPos getPosition(int x, int y, int z) { + return new BlockPos(x, y, z); + } + + @Override + public void updateLightingForBlock(BlockPos blockPos) { + getLevel().getChunkSource().getLightEngine().checkBlock(blockPos); + } + + @Override + public boolean updateTileEntity(BlockPos blockPos, LinCompoundTag tag) { + // We will assume that the tile entity was created for us, + // though we do not do this on the other versions + BlockEntity blockEntity = getLevel().getBlockEntity(blockPos); + if (blockEntity == null) { + return false; + } + net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeLin(tag); + blockEntity.loadWithComponents((CompoundTag) nativeTag, DedicatedServer.getServer().registryAccess()); + return true; + } + + @Override + public void notifyBlockUpdate( + LevelChunk levelChunk, BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { + getLevel().sendBlockUpdated(blockPos, oldState, newState, UPDATE | NOTIFY); + } + } + + @Override + public boolean isChunkTicking(LevelChunk levelChunk) { + return levelChunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING); + } + + @Override + public void markBlockChanged(LevelChunk levelChunk, BlockPos blockPos) { + if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { + ((ServerChunkCache) getLevel().getChunkSource()).blockChanged(blockPos); + } + } + + @Override + public void notifyNeighbors( + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + Level level = getLevel(); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + level.blockUpdated(blockPos, oldState.getBlock()); + } else { + // When we don't want events, manually run the physics without them. + // Un-nest neighbour updating + for (Direction direction : NEIGHBOUR_ORDER) { + BlockPos shifted = blockPos.relative(direction); + level.getBlockState(shifted).handleNeighborChanged(level, shifted, oldState.getBlock(), ExperimentalRedstoneUtils.initialOrientation(level, null, null), false); + } + } + if (newState.hasAnalogOutputSignal()) { + level.updateNeighbourForOutputSignal(blockPos, newState.getBlock()); + } + } + + @Override + public void updateNeighbors( + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState, + int recursionLimit + ) { + Level level = getLevel(); + // a == updateNeighbors + // b == updateDiagonalNeighbors + oldState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + CraftWorld craftWorld = level.getWorld(); + if (craftWorld != null) { + BlockPhysicsEvent event = new BlockPhysicsEvent( + craftWorld.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()), + CraftBlockData.fromData(newState) + ); + level.getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + } + } + newState.triggerEvent(level, blockPos, NOTIFY, recursionLimit); + newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); + } + + @Override + public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { + Level world = getLevel(); + newState.onPlace(world, pos, oldState, false); + } + + @Override + public void onBlockStateChange( + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + getLevel().onBlockStateChange(blockPos, oldState, newState); + } + + private synchronized void flushAsync(final boolean sendChunks) { + final Set changes = Set.copyOf(cachedChanges); + cachedChanges.clear(); + final Set toSend; + if (sendChunks) { + toSend = Set.copyOf(cachedChunksToSend); + cachedChunksToSend.clear(); + } else { + toSend = Collections.emptySet(); + } + RunnableVal runnableVal = new RunnableVal<>() { + @Override + public void run(Object value) { + changes.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, + sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) + )); + if (!sendChunks) { + return; + } + for (IntPair chunk : toSend) { + PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z()); + } + } + }; + TaskManager.taskManager().async(() -> TaskManager.taskManager().sync(runnableVal)); + } + + @Override + public synchronized void flush() { + RunnableVal runnableVal = new RunnableVal<>() { + @Override + public void run(Object value) { + cachedChanges.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, + sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) + )); + for (IntPair chunk : cachedChunksToSend) { + PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z()); + } + } + }; + if (Fawe.isMainThread()) { + runnableVal.run(); + } else { + TaskManager.taskManager().sync(runnableVal); + } + cachedChanges.clear(); + cachedChunksToSend.clear(); + } + + private record CachedChange( + LevelChunk levelChunk, + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState blockState + ) { + + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightGetBlocks.java new file mode 100644 index 000000000..1d04075f3 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightGetBlocks.java @@ -0,0 +1,1199 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_3; + +import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; +import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.math.IntPair; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import com.fastasyncworldedit.core.queue.implementation.QueueHandler; +import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; +import com.fastasyncworldedit.core.util.MathMan; +import com.fastasyncworldedit.core.util.NbtUtils; +import com.fastasyncworldedit.core.util.collection.AdaptedMap; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import io.papermc.lib.PaperLib; +import io.papermc.paper.event.block.BeaconDeactivatedEvent; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.IdMap; +import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.IntTag; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.util.BitStorage; +import net.minecraft.util.ZeroBitStorage; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.entity.BeaconBlockEntity; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.HashMapPalette; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.LinearPalette; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.apache.logging.log4j.Logger; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTagType; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.AbstractCollection; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Future; +import java.util.concurrent.Semaphore; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Function; + +import static net.minecraft.core.registries.Registries.BIOME; + +public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private static final Function posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); + public static final Function NMS_TO_TILE = ((PaperweightFaweAdapter) WorldEditPlugin + .getInstance() + .getBukkitImplAdapter()).blockEntityToCompoundTag(); + private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin + .getInstance() + .getBukkitImplAdapter()); + private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); + private final ReentrantLock callLock = new ReentrantLock(); + private final ServerLevel serverLevel; + private final int chunkX; + private final int chunkZ; + private final IntPair chunkPos; + private final int minHeight; + private final int maxHeight; + private final int minSectionPosition; + private final int maxSectionPosition; + private final Registry biomeRegistry; + private final IdMap> biomeHolderIdMap; + private final ConcurrentHashMap copies = new ConcurrentHashMap<>(); + private final Object sendLock = new Object(); + private LevelChunkSection[] sections; + private LevelChunk levelChunk; + private DataLayer[] blockLight; + private DataLayer[] skyLight; + private boolean createCopy = false; + private boolean forceLoadSections = true; + private boolean lightUpdate = false; + private int copyKey = 0; + + public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { + this(((CraftWorld) world).getHandle(), chunkX, chunkZ); + } + + public PaperweightGetBlocks(ServerLevel serverLevel, int chunkX, int chunkZ) { + super(serverLevel.getMinY() >> 4, (serverLevel.getMaxY() - 1) >> 4); + this.serverLevel = serverLevel; + this.chunkX = chunkX; + this.chunkZ = chunkZ; + this.minHeight = serverLevel.getMinY(); + this.maxHeight = serverLevel.getMaxY() - 1; // Minecraft max limit is exclusive. + this.minSectionPosition = minHeight >> 4; + this.maxSectionPosition = maxHeight >> 4; + this.skyLight = new DataLayer[getSectionCount()]; + this.blockLight = new DataLayer[getSectionCount()]; + this.biomeRegistry = serverLevel.registryAccess().lookupOrThrow(BIOME); + this.biomeHolderIdMap = biomeRegistry.asHolderIdMap(); + this.chunkPos = new IntPair(chunkX, chunkZ); + } + + public int getChunkX() { + return chunkX; + } + + public int getChunkZ() { + return chunkZ; + } + + @Override + public boolean isCreateCopy() { + return createCopy; + } + + @Override + public int setCreateCopy(boolean createCopy) { + if (!callLock.isHeldByCurrentThread()) { + throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); + } + this.createCopy = createCopy; + // Increment regardless of whether copy will be created or not to return null from getCopy() + return ++this.copyKey; + } + + @Override + public IChunkGet getCopy(final int key) { + return copies.remove(key); + } + + @Override + public void lockCall() { + this.callLock.lock(); + } + + @Override + public void unlockCall() { + this.callLock.unlock(); + } + + @Override + public void setLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { + if (light != null) { + lightUpdate = true; + try { + fillLightNibble(light, LightLayer.BLOCK, minSectionPosition, maxSectionPosition); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + @Override + public void setSkyLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { + if (light != null) { + lightUpdate = true; + try { + fillLightNibble(light, LightLayer.SKY, minSectionPosition, maxSectionPosition); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + @Override + public void setHeightmapToGet(HeightMapType type, int[] data) { + // height + 1 to match server internal + BitArrayUnstretched bitArray = new BitArrayUnstretched(MathMan.log2nlz(getChunk().getHeight() + 1), 256); + bitArray.fromRaw(data); + Heightmap.Types nativeType = Heightmap.Types.valueOf(type.name()); + Heightmap heightMap = getChunk().heightmaps.get(nativeType); + heightMap.setRawData(getChunk(), nativeType, bitArray.getData()); + } + + @Override + public int getMaxY() { + return maxHeight; + } + + @Override + public int getMinY() { + return minHeight; + } + + @Override + public BiomeType getBiomeType(int x, int y, int z) { + LevelChunkSection section = getSections(false)[(y >> 4) - getMinSectionPosition()]; + Holder biomes = section.getNoiseBiome(x >> 2, (y & 15) >> 2, z >> 2); + return PaperweightPlatformAdapter.adapt(biomes, serverLevel); + } + + @Override + public void removeSectionLighting(int layer, boolean sky) { + SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.BLOCK).getDataLayerData( + sectionPos); + if (dataLayer != null) { + lightUpdate = true; + synchronized (dataLayer) { + byte[] bytes = dataLayer.getData(); + Arrays.fill(bytes, (byte) 0); + } + } + if (sky) { + SectionPos sectionPos1 = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer1 = serverLevel + .getChunkSource() + .getLightEngine() + .getLayerListener(LightLayer.SKY) + .getDataLayerData(sectionPos1); + if (dataLayer1 != null) { + lightUpdate = true; + synchronized (dataLayer1) { + byte[] bytes = dataLayer1.getData(); + Arrays.fill(bytes, (byte) 0); + } + } + } + } + + @Override + public FaweCompoundTag tile(final int x, final int y, final int z) { + BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( + chunkX << 4), y, (z & 15) + ( + chunkZ << 4))); + if (blockEntity == null) { + return null; + } + return NMS_TO_TILE.apply(blockEntity); + + } + + @Override + public Map tiles() { + Map nmsTiles = getChunk().getBlockEntities(); + if (nmsTiles.isEmpty()) { + return Collections.emptyMap(); + } + return AdaptedMap.immutable(nmsTiles, posNms2We, NMS_TO_TILE); + } + + @Override + public int getSkyLight(int x, int y, int z) { + int layer = y >> 4; + int alayer = layer - getMinSectionPosition(); + if (skyLight[alayer] == null) { + SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer = + serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.SKY).getDataLayerData(sectionPos); + // If the server hasn't generated the section's NibbleArray yet, it will be null + if (dataLayer == null) { + byte[] LAYER_COUNT = new byte[2048]; + // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. + Arrays.fill(LAYER_COUNT, (byte) 15); + dataLayer = new DataLayer(LAYER_COUNT); + ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( + LightLayer.BLOCK, + sectionPos, + dataLayer + ); + } + skyLight[alayer] = dataLayer; + } + return skyLight[alayer].get(x & 15, y & 15, z & 15); + } + + @Override + public int getEmittedLight(int x, int y, int z) { + int layer = y >> 4; + int alayer = layer - getMinSectionPosition(); + if (blockLight[alayer] == null) { + serverLevel.getRawBrightness(new BlockPos(1, 1, 1), 5); + SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer = serverLevel + .getChunkSource() + .getLightEngine() + .getLayerListener(LightLayer.BLOCK) + .getDataLayerData(sectionPos); + // If the server hasn't generated the section's DataLayer yet, it will be null + if (dataLayer == null) { + byte[] LAYER_COUNT = new byte[2048]; + // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. + Arrays.fill(LAYER_COUNT, (byte) 15); + dataLayer = new DataLayer(LAYER_COUNT); + ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos, + dataLayer + ); + } + blockLight[alayer] = dataLayer; + } + return blockLight[alayer].get(x & 15, y & 15, z & 15); + } + + @Override + public int[] getHeightMap(HeightMapType type) { + long[] longArray = getChunk().heightmaps.get(Heightmap.Types.valueOf(type.name())).getRawData(); + BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256, longArray); + return bitArray.toRaw(new int[256]); + } + + @Override + public @Nullable FaweCompoundTag entity(final UUID uuid) { + ensureLoaded(serverLevel, chunkX, chunkZ); + List entities = PaperweightPlatformAdapter.getEntities(getChunk()); + Entity entity = null; + for (Entity e : entities) { + if (e.getUUID().equals(uuid)) { + entity = e; + break; + } + } + if (entity != null) { + org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); + return FaweCompoundTag.of(BukkitAdapter.adapt(bukkitEnt).getState().getNbt()); + } + for (FaweCompoundTag tag : entities()) { + if (uuid.equals(NbtUtils.uuid(tag))) { + return tag; + } + } + return null; + } + + @Override + public Collection entities() { + ensureLoaded(serverLevel, chunkX, chunkZ); + List entities = PaperweightPlatformAdapter.getEntities(getChunk()); + if (entities.isEmpty()) { + return Collections.emptyList(); + } + int size = entities.size(); + return new AbstractCollection<>() { + @Override + public int size() { + return size; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean contains(Object get) { + if (!(get instanceof FaweCompoundTag getTag)) { + return false; + } + UUID getUUID = NbtUtils.uuid(getTag); + for (Entity entity : entities) { + UUID uuid = entity.getUUID(); + if (uuid.equals(getUUID)) { + return true; + } + } + return false; + } + + @Nonnull + @Override + public Iterator iterator() { + Iterable result = entities.stream().map(input -> { + CompoundTag tag = new CompoundTag(); + input.save(tag); + return FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(tag)); + })::iterator; + return result.iterator(); + } + }; + + } + + private void removeEntity(Entity entity) { + entity.discard(); + } + + public LevelChunk ensureLoaded(ServerLevel nmsWorld, int chunkX, int chunkZ) { + return PaperweightPlatformAdapter.ensureLoaded(nmsWorld, chunkX, chunkZ); + } + + @Override + @SuppressWarnings("rawtypes") + public synchronized > T call(IChunkSet set, Runnable finalizer) { + if (!callLock.isHeldByCurrentThread()) { + throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked."); + } + forceLoadSections = false; + LevelChunk nmsChunk = ensureLoaded(serverLevel, chunkX, chunkZ); + PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(nmsChunk) : null; + if (createCopy) { + if (copies.containsKey(copyKey)) { + throw new IllegalStateException("Copy key already used."); + } + copies.put(copyKey, copy); + } + try { + // Remove existing tiles. Create a copy so that we can remove blocks + Map chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); + List beacons = null; + if (!chunkTiles.isEmpty()) { + for (Map.Entry entry : chunkTiles.entrySet()) { + final BlockPos pos = entry.getKey(); + final int lx = pos.getX() & 15; + final int ly = pos.getY(); + final int lz = pos.getZ() & 15; + final int layer = ly >> 4; + if (!set.hasSection(layer)) { + continue; + } + + int ordinal = set.getBlock(lx, ly, lz).getOrdinal(); + if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) { + BlockEntity tile = entry.getValue(); + if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) { + if (beacons == null) { + beacons = new ArrayList<>(); + } + beacons.add(tile); + PaperweightPlatformAdapter.removeBeacon(tile, nmsChunk); + continue; + } + nmsChunk.removeBlockEntity(tile.getBlockPos()); + if (createCopy) { + copy.storeTile(tile); + } + } + } + } + final BiomeType[][] biomes = set.getBiomes(); + + int bitMask = 0; + synchronized (nmsChunk) { + LevelChunkSection[] levelChunkSections = nmsChunk.getSections(); + + for (int layerNo = getMinSectionPosition(); layerNo <= getMaxSectionPosition(); layerNo++) { + + int getSectionIndex = layerNo - getMinSectionPosition(); + int setSectionIndex = layerNo - set.getMinSectionPosition(); + + if (!set.hasSection(layerNo)) { + // No blocks, but might be biomes present. Handle this lazily. + if (biomes == null) { + continue; + } + if (layerNo < set.getMinSectionPosition() || layerNo > set.getMaxSectionPosition()) { + continue; + } + if (biomes[setSectionIndex] != null) { + synchronized (super.sectionLocks[getSectionIndex]) { + LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; + if (createCopy && existingSection != null) { + copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); + } + + if (existingSection == null) { + PalettedContainer> biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer( + biomes[setSectionIndex], + biomeHolderIdMap + ); + LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + new char[4096], + adapter, + biomeRegistry, + biomeData + ); + if (PaperweightPlatformAdapter.setSectionAtomic( + serverLevel.getWorld().getName(), + chunkPos, + levelChunkSections, + null, + newSection, + getSectionIndex + )) { + updateGet(nmsChunk, levelChunkSections, newSection, new char[4096], getSectionIndex); + continue; + } else { + existingSection = levelChunkSections[getSectionIndex]; + if (existingSection == null) { + LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, + getSectionIndex + ); + continue; + } + } + } else { + PalettedContainer> paletteBiomes = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); + if (paletteBiomes != null) { + PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes); + } + } + } + } + continue; + } + + bitMask |= 1 << getSectionIndex; + + // setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to + // this chunk GET when #updateGet is called. Future dords, please listen this time. + char[] tmp = set.load(layerNo); + char[] setArr = new char[tmp.length]; + System.arraycopy(tmp, 0, setArr, 0, tmp.length); + + // synchronise on internal section to avoid circular locking with a continuing edit if the chunk was + // submitted to keep loaded internal chunks to queue target size. + synchronized (super.sectionLocks[getSectionIndex]) { + + LevelChunkSection newSection; + LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; + // Don't attempt to tick section whilst we're editing + if (existingSection != null) { + PaperweightPlatformAdapter.clearCounts(existingSection); + } + + if (createCopy) { + char[] tmpLoad = loadPrivately(layerNo); + char[] copyArr = new char[4096]; + System.arraycopy(tmpLoad, 0, copyArr, 0, 4096); + copy.storeSection(getSectionIndex, copyArr); + if (biomes != null && existingSection != null) { + copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); + } + } + + if (existingSection == null) { + PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( + biomeHolderIdMap, + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), + PalettedContainer.Strategy.SECTION_BIOMES + ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + setArr, + adapter, + biomeRegistry, + biomeData + ); + if (PaperweightPlatformAdapter.setSectionAtomic( + serverLevel.getWorld().getName(), + chunkPos, + levelChunkSections, + null, + newSection, + getSectionIndex + )) { + updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); + continue; + } else { + existingSection = levelChunkSections[getSectionIndex]; + if (existingSection == null) { + LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, + getSectionIndex + ); + continue; + } + } + } + + //ensure that the server doesn't try to tick the chunksection while we're editing it. (Again) + PaperweightPlatformAdapter.clearCounts(existingSection); + DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); + + // Synchronize to prevent further acquisitions + synchronized (lock) { + lock.acquire(); // Wait until we have the lock + lock.release(); + try { + sectionLock.writeLock().lock(); + if (this.getChunk() != nmsChunk) { + this.levelChunk = nmsChunk; + this.sections = null; + this.reset(); + } else if (existingSection != getSections(false)[getSectionIndex]) { + this.sections[getSectionIndex] = existingSection; + this.reset(); + } else if (!Arrays.equals( + update(getSectionIndex, new char[4096], true), + loadPrivately(layerNo) + )) { + this.reset(layerNo); + /*} else if (lock.isModified()) { + this.reset(layerNo);*/ + } + } finally { + sectionLock.writeLock().unlock(); + } + + PalettedContainer> biomeData = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); + + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + this::loadPrivately, + setArr, + adapter, + biomeRegistry, + biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() + ); + if (!PaperweightPlatformAdapter.setSectionAtomic( + serverLevel.getWorld().getName(), + chunkPos, + levelChunkSections, + existingSection, + newSection, + getSectionIndex + )) { + LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, + getSectionIndex + ); + } else { + updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); + } + } + } + } + + Map heightMaps = set.getHeightMaps(); + for (Map.Entry entry : heightMaps.entrySet()) { + PaperweightGetBlocks.this.setHeightmapToGet(entry.getKey(), entry.getValue()); + } + PaperweightGetBlocks.this.setLightingToGet( + set.getLight(), + set.getMinSectionPosition(), + set.getMaxSectionPosition() + ); + PaperweightGetBlocks.this.setSkyLightingToGet( + set.getSkyLight(), + set.getMinSectionPosition(), + set.getMaxSectionPosition() + ); + + Runnable[] syncTasks = null; + + int bx = chunkX << 4; + int bz = chunkZ << 4; + + // Call beacon deactivate events here synchronously + // list will be null on spigot, so this is an implicit isPaper check + if (beacons != null && !beacons.isEmpty()) { + final List finalBeacons = beacons; + + syncTasks = new Runnable[4]; + + syncTasks[3] = () -> { + for (BlockEntity beacon : finalBeacons) { + BeaconBlockEntity.playSound(beacon.getLevel(), beacon.getBlockPos(), SoundEvents.BEACON_DEACTIVATE); + new BeaconDeactivatedEvent(CraftBlock.at(beacon.getLevel(), beacon.getBlockPos())).callEvent(); + } + }; + } + + Set entityRemoves = set.getEntityRemoves(); + if (entityRemoves != null && !entityRemoves.isEmpty()) { + if (syncTasks == null) { + syncTasks = new Runnable[3]; + } + + syncTasks[2] = () -> { + Set entitiesRemoved = new HashSet<>(); + final List entities = PaperweightPlatformAdapter.getEntities(nmsChunk); + + for (Entity entity : entities) { + UUID uuid = entity.getUUID(); + if (entityRemoves.contains(uuid)) { + if (createCopy) { + copy.storeEntity(entity); + } + removeEntity(entity); + entitiesRemoved.add(uuid); + entityRemoves.remove(uuid); + } + } + if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { + for (UUID uuid : entityRemoves) { + Entity entity = serverLevel.getEntities().get(uuid); + if (entity != null) { + removeEntity(entity); + } + } + } + // Only save entities that were actually removed to history + set.getEntityRemoves().clear(); + set.getEntityRemoves().addAll(entitiesRemoved); + }; + } + + Collection entities = set.entities(); + if (entities != null && !entities.isEmpty()) { + if (syncTasks == null) { + syncTasks = new Runnable[2]; + } + + syncTasks[1] = () -> { + Iterator iterator = entities.iterator(); + while (iterator.hasNext()) { + final FaweCompoundTag nativeTag = iterator.next(); + final LinCompoundTag linTag = nativeTag.linTag(); + final LinStringTag idTag = linTag.findTag("Id", LinTagType.stringTag()); + final LinListTag posTag = linTag.findListTag("Pos", LinTagType.doubleTag()); + final LinListTag rotTag = linTag.findListTag("Rotation", LinTagType.floatTag()); + if (idTag == null || posTag == null || rotTag == null) { + LOGGER.error("Unknown entity tag: {}", nativeTag); + continue; + } + final double x = posTag.get(0).valueAsDouble(); + final double y = posTag.get(1).valueAsDouble(); + final double z = posTag.get(2).valueAsDouble(); + final float yaw = rotTag.get(0).valueAsFloat(); + final float pitch = rotTag.get(1).valueAsFloat(); + final String id = idTag.value(); + + EntityType type = EntityType.byString(id).orElse(null); + if (type != null) { + Entity entity = type.create(serverLevel, EntitySpawnReason.COMMAND); + if (entity != null) { + final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(linTag); + for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + entity.load(tag); + entity.absMoveTo(x, y, z, yaw, pitch); + entity.setUUID(NbtUtils.uuid(nativeTag)); + if (!serverLevel.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { + LOGGER.warn( + "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", + id, + serverLevel.getWorld().getName(), + x, + y, + z + ); + // Unsuccessful create should not be saved to history + iterator.remove(); + } + } + } + } + }; + } + + // set tiles + Map tiles = set.tiles(); + if (tiles != null && !tiles.isEmpty()) { + if (syncTasks == null) { + syncTasks = new Runnable[1]; + } + + syncTasks[0] = () -> { + for (final Map.Entry entry : tiles.entrySet()) { + final FaweCompoundTag nativeTag = entry.getValue(); + final BlockVector3 blockHash = entry.getKey(); + final int x = blockHash.x() + bx; + final int y = blockHash.y(); + final int z = blockHash.z() + bz; + final BlockPos pos = new BlockPos(x, y, z); + + synchronized (serverLevel) { + BlockEntity tileEntity = serverLevel.getBlockEntity(pos); + if (tileEntity == null || tileEntity.isRemoved()) { + serverLevel.removeBlockEntity(pos); + tileEntity = serverLevel.getBlockEntity(pos); + } + if (tileEntity != null) { + final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag()); + tag.put("x", IntTag.valueOf(x)); + tag.put("y", IntTag.valueOf(y)); + tag.put("z", IntTag.valueOf(z)); + tileEntity.loadWithComponents(tag, DedicatedServer.getServer().registryAccess()); + } + } + } + }; + } + + Runnable callback; + if (bitMask == 0 && biomes == null && !lightUpdate) { + callback = null; + } else { + int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; + callback = () -> { + // Set Modified + nmsChunk.setLightCorrect(true); // Set Modified + nmsChunk.mustNotSave = false; + nmsChunk.markUnsaved(); + // send to player + if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING || finalMask == 0 && biomes != null) { + this.send(); + } + if (finalizer != null) { + finalizer.run(); + } + }; + } + if (syncTasks != null) { + QueueHandler queueHandler = Fawe.instance().getQueueHandler(); + Runnable[] finalSyncTasks = syncTasks; + + // Chain the sync tasks and the callback + Callable chain = () -> { + try { + // Run the sync tasks + for (Runnable task : finalSyncTasks) { + if (task != null) { + task.run(); + } + } + if (callback == null) { + if (finalizer != null) { + queueHandler.async(finalizer, null); + } + return null; + } else { + return queueHandler.async(callback, null); + } + } catch (Throwable e) { + e.printStackTrace(); + throw e; + } + }; + //noinspection unchecked - required at compile time + return (T) (Future) queueHandler.sync(chain); + } else { + if (callback == null) { + if (finalizer != null) { + finalizer.run(); + } + } else { + callback.run(); + } + } + } + return null; + } catch (Throwable e) { + e.printStackTrace(); + return null; + } finally { + forceLoadSections = true; + } + } + + private void updateGet( + LevelChunk nmsChunk, + LevelChunkSection[] chunkSections, + LevelChunkSection section, + char[] arr, + int layer + ) { + try { + sectionLock.writeLock().lock(); + if (this.getChunk() != nmsChunk) { + this.levelChunk = nmsChunk; + this.sections = new LevelChunkSection[chunkSections.length]; + System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); + this.reset(); + } + if (this.sections == null) { + this.sections = new LevelChunkSection[chunkSections.length]; + System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); + } + if (this.sections[layer] != section) { + // Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords + this.sections[layer] = new LevelChunkSection[]{section}.clone()[0]; + } + } finally { + sectionLock.writeLock().unlock(); + } + this.blocks[layer] = arr; + } + + private char[] loadPrivately(int layer) { + layer -= getMinSectionPosition(); + if (super.sections[layer] != null) { + synchronized (super.sectionLocks[layer]) { + if (super.sections[layer].isFull() && super.blocks[layer] != null) { + return super.blocks[layer]; + } + } + } + return PaperweightGetBlocks.this.update(layer, null, true); + } + + @Override + public void send() { + synchronized (sendLock) { + PaperweightPlatformAdapter.sendChunk(new IntPair(chunkX, chunkZ), serverLevel, chunkX, chunkZ); + } + } + + /** + * Update a given (nullable) data array to the current data stored in the server's chunk, associated with this + * {@link PaperweightPlatformAdapter} instance. Not synchronised to the {@link PaperweightPlatformAdapter} instance as synchronisation + * is handled where necessary in the method, and should otherwise be handled correctly by this method's caller. + * + * @param layer layer index (0 may denote a negative layer in the world, e.g. at y=-32) + * @param data array to be updated/filled with data or null + * @param aggressive if the cached section array should be re-acquired. + * @return the given array to be filled with data, or a new array if null is given. + */ + @Override + @SuppressWarnings("unchecked") + public char[] update(int layer, char[] data, boolean aggressive) { + LevelChunkSection section = getSections(aggressive)[layer]; + // Section is null, return empty array + if (section == null) { + data = new char[4096]; + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); + return data; + } + if (data != null && data.length != 4096) { + data = new char[4096]; + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); + } + if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) { + data = new char[4096]; + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); + } + Semaphore lock = PaperweightPlatformAdapter.applyLock(section); + synchronized (lock) { + // Efficiently convert ChunkSection to raw data + try { + lock.acquire(); + + final PalettedContainer blocks = section.getStates(); + final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocks); + final BitStorage bits = (BitStorage) PaperweightPlatformAdapter.fieldStorage.get(dataObject); + + if (bits instanceof ZeroBitStorage) { + Arrays.fill(data, adapter.adaptToChar(blocks.get(0, 0, 0))); // get(int) is only public on paper + return data; + } + + final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get(dataObject); + + final int bitsPerEntry = bits.getBits(); + final long[] blockStates = bits.getRaw(); + + new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).toRaw(data); + + int num_palette; + if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { + num_palette = palette.getSize(); + } else { + // The section's palette is the global block palette. + for (int i = 0; i < 4096; i++) { + char paletteVal = data[i]; + char ordinal = adapter.ibdIDToOrdinal(paletteVal); + data[i] = ordinal; + } + return data; + } + + char[] paletteToOrdinal = FaweCache.INSTANCE.PALETTE_TO_BLOCK_CHAR.get(); + try { + if (num_palette != 1) { + for (int i = 0; i < num_palette; i++) { + char ordinal = ordinal(palette.valueFor(i), adapter); + paletteToOrdinal[i] = ordinal; + } + for (int i = 0; i < 4096; i++) { + char paletteVal = data[i]; + char val = paletteToOrdinal[paletteVal]; + if (val == Character.MAX_VALUE) { + val = ordinal(palette.valueFor(i), adapter); + paletteToOrdinal[i] = val; + } + data[i] = val; + } + } else { + char ordinal = ordinal(palette.valueFor(0), adapter); + Arrays.fill(data, ordinal); + } + } finally { + for (int i = 0; i < num_palette; i++) { + paletteToOrdinal[i] = Character.MAX_VALUE; + } + } + return data; + } catch (IllegalAccessException | InterruptedException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } finally { + lock.release(); + } + } + } + + private char ordinal(BlockState ibd, PaperweightFaweAdapter adapter) { + if (ibd == null) { + return BlockTypesCache.ReservedIDs.AIR; + } else { + return adapter.adaptToChar(ibd); + } + } + + public LevelChunkSection[] getSections(boolean force) { + force &= forceLoadSections; + LevelChunkSection[] tmp = sections; + if (tmp == null || force) { + try { + sectionLock.writeLock().lock(); + tmp = sections; + if (tmp == null || force) { + LevelChunkSection[] chunkSections = getChunk().getSections(); + tmp = new LevelChunkSection[chunkSections.length]; + System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length); + sections = tmp; + } + } finally { + sectionLock.writeLock().unlock(); + } + } + return tmp; + } + + public LevelChunk getChunk() { + LevelChunk levelChunk = this.levelChunk; + if (levelChunk == null) { + synchronized (this) { + levelChunk = this.levelChunk; + if (levelChunk == null) { + this.levelChunk = levelChunk = ensureLoaded(this.serverLevel, chunkX, chunkZ); + } + } + } + return levelChunk; + } + + private void fillLightNibble(char[][] light, LightLayer lightLayer, int minSectionPosition, int maxSectionPosition) { + for (int Y = 0; Y <= maxSectionPosition - minSectionPosition; Y++) { + if (light[Y] == null) { + continue; + } + SectionPos sectionPos = SectionPos.of(levelChunk.getPos(), Y + minSectionPosition); + DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(lightLayer).getDataLayerData( + sectionPos); + if (dataLayer == null) { + byte[] LAYER_COUNT = new byte[2048]; + Arrays.fill(LAYER_COUNT, lightLayer == LightLayer.SKY ? (byte) 15 : (byte) 0); + dataLayer = new DataLayer(LAYER_COUNT); + ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( + lightLayer, + sectionPos, + dataLayer + ); + } + synchronized (dataLayer) { + for (int x = 0; x < 16; x++) { + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + int i = y << 8 | z << 4 | x; + if (light[Y][i] < 16) { + dataLayer.set(x, y, z, light[Y][i]); + } + } + } + } + } + } + } + + private PalettedContainer> setBiomesToPalettedContainer( + final BiomeType[][] biomes, + final int sectionIndex, + final PalettedContainerRO> data + ) { + BiomeType[] sectionBiomes; + if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { + return null; + } + PalettedContainer> biomeData = data.recreate(); + for (int y = 0, index = 0; y < 4; y++) { + for (int z = 0; z < 4; z++) { + for (int x = 0; x < 4; x++, index++) { + BiomeType biomeType = sectionBiomes[index]; + if (biomeType == null) { + biomeData.set(x, y, z, data.get(x, y, z)); + } else { + biomeData.set( + x, + y, + z, + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) + ); + } + } + } + } + return biomeData; + } + + @Override + public boolean hasSection(int layer) { + layer -= getMinSectionPosition(); + return getSections(false)[layer] != null; + } + + @Override + @SuppressWarnings("unchecked") + public synchronized boolean trim(boolean aggressive) { + skyLight = new DataLayer[getSectionCount()]; + blockLight = new DataLayer[getSectionCount()]; + if (aggressive) { + sectionLock.writeLock().lock(); + sections = null; + levelChunk = null; + sectionLock.writeLock().unlock(); + return super.trim(true); + } else if (sections == null) { + // don't bother trimming if there are no sections stored. + return true; + } else { + for (int i = getMinSectionPosition(); i <= getMaxSectionPosition(); i++) { + int layer = i - getMinSectionPosition(); + if (!hasSection(i) || !super.sections[layer].isFull()) { + continue; + } + LevelChunkSection existing = getSections(true)[layer]; + try { + final PalettedContainer blocksExisting = existing.getStates(); + + final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocksExisting); + final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get( + dataObject); + int paletteSize; + + if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { + paletteSize = palette.getSize(); + } else { + super.trim(false, i); + continue; + } + if (paletteSize == 1) { + //If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks. + continue; + } + super.trim(false, i); + } catch (IllegalAccessException ignored) { + super.trim(false, i); + } + } + return true; + } + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightGetBlocks_Copy.java new file mode 100644 index 000000000..60649041b --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightGetBlocks_Copy.java @@ -0,0 +1,276 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_3; + +import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; +import com.fastasyncworldedit.core.queue.IBlocks; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import com.fastasyncworldedit.core.util.NbtUtils; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.BlockVector3; +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.BlockTypesCache; +import io.papermc.lib.PaperLib; +import net.minecraft.core.Holder; +import net.minecraft.nbt.Tag; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinCompoundTag; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Future; + +public class PaperweightGetBlocks_Copy implements IChunkGet { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private final Map tiles = new HashMap<>(); + private final Set entities = new HashSet<>(); + private final char[][] blocks; + private final int minHeight; + private final int maxHeight; + final ServerLevel serverLevel; + final LevelChunk levelChunk; + private Holder[][] biomes = null; + + protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { + this.levelChunk = levelChunk; + this.serverLevel = levelChunk.level; + this.minHeight = serverLevel.getMinY(); + this.maxHeight = serverLevel.getMaxY() - 1; // Minecraft max limit is exclusive. + this.blocks = new char[getSectionCount()][]; + } + + protected void storeTile(BlockEntity blockEntity) { + @SuppressWarnings("unchecked") + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + tiles.put( + BlockVector3.at( + blockEntity.getBlockPos().getX(), + blockEntity.getBlockPos().getY(), + blockEntity.getBlockPos().getZ() + ), + FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(blockEntity.saveWithId(DedicatedServer + .getServer() + .registryAccess()))) + ); + } + + protected void storeEntity(Entity entity) { + @SuppressWarnings("unchecked") + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); + entity.save(compoundTag); + entities.add(FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(compoundTag))); + } + + @Override + public Collection entities() { + return this.entities; + } + + @Override + public @Nullable FaweCompoundTag entity(final UUID uuid) { + for (FaweCompoundTag tag : entities) { + if (uuid.equals(NbtUtils.uuid(tag))) { + return tag; + } + } + return null; + } + + @Override + public boolean isCreateCopy() { + return false; + } + + @Override + public int setCreateCopy(boolean createCopy) { + return -1; + } + + @Override + public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { + } + + @Override + public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { + } + + @Override + public void setHeightmapToGet(HeightMapType type, int[] data) { + } + + @Override + public int getMaxY() { + return maxHeight; + } + + @Override + public int getMinY() { + return minHeight; + } + + @Override + public int getMaxSectionPosition() { + return maxHeight >> 4; + } + + @Override + public int getMinSectionPosition() { + return minHeight >> 4; + } + + @Override + public BiomeType getBiomeType(int x, int y, int z) { + Holder biome = biomes[(y >> 4) - getMinSectionPosition()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2]; + return PaperweightPlatformAdapter.adapt(biome, serverLevel); + } + + @Override + public void removeSectionLighting(int layer, boolean sky) { + } + + @Override + public boolean trim(boolean aggressive, int layer) { + return false; + } + + @Override + public IBlocks reset() { + return null; + } + + @Override + public int getSectionCount() { + return serverLevel.getSectionsCount(); + } + + protected void storeSection(int layer, char[] data) { + blocks[layer] = data; + } + + protected void storeBiomes(int layer, PalettedContainerRO> biomeData) { + if (biomes == null) { + biomes = new Holder[getSectionCount()][]; + } + if (biomes[layer] == null) { + biomes[layer] = new Holder[64]; + } + if (biomeData instanceof PalettedContainer> palettedContainer) { + if (PaperLib.isPaper()) { + for (int i = 0; i < 64; i++) { + biomes[layer][i] = palettedContainer.get(i); // Only public on paper + } + } else { + try { + for (int i = 0; i < 64; i++) { + biomes[layer][i] = (Holder) PaperweightPlatformAdapter.PALETTED_CONTAINER_GET.invoke(i); + } + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + } else { + LOGGER.error( + "Cannot correctly save biomes to history. Expected class type {} but got {}", + PalettedContainer.class.getSimpleName(), + biomeData.getClass().getSimpleName() + ); + } + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + BlockState state = BlockTypesCache.states[get(x, y, z)]; + return state.toBaseBlock((IBlocks) this, x, y, z); + } + + @Override + public boolean hasSection(int layer) { + layer -= getMinSectionPosition(); + return blocks[layer] != null; + } + + @Override + public char[] load(int layer) { + layer -= getMinSectionPosition(); + if (blocks[layer] == null) { + blocks[layer] = new char[4096]; + Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR); + } + return blocks[layer]; + } + + @Override + public char[] loadIfPresent(int layer) { + layer -= getMinSectionPosition(); + return blocks[layer]; + } + + @Override + public BlockState getBlock(int x, int y, int z) { + return BlockTypesCache.states[get(x, y, z)]; + } + + @Override + public Map tiles() { + return tiles; + } + + @Override + public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) { + return tiles.get(BlockVector3.at(x, y, z)); + } + + @Override + public int getSkyLight(int x, int y, int z) { + return 0; + } + + @Override + public int getEmittedLight(int x, int y, int z) { + return 0; + } + + @Override + public int[] getHeightMap(HeightMapType type) { + return new int[0]; + } + + @Override + public > T call(IChunkSet set, Runnable finalize) { + return null; + } + + public char get(int x, int y, int z) { + final int layer = (y >> 4) - getMinSectionPosition(); + final int index = (y & 15) << 8 | z << 4 | x; + return blocks[layer][index]; + } + + + @Override + public boolean trim(boolean aggressive) { + return false; + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightMapChunkUtil.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightMapChunkUtil.java new file mode 100644 index 000000000..e972a9dbc --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightMapChunkUtil.java @@ -0,0 +1,34 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_3; + +import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; + +//TODO un-very-break-this +public class PaperweightMapChunkUtil extends MapChunkUtil { + + public PaperweightMapChunkUtil() throws NoSuchFieldException { + fieldX = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("TWO_MEGABYTES", "a")); + fieldZ = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("x", "b")); + fieldBitMask = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("z", "c")); + fieldHeightMap = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("heightmaps", "b")); + fieldChunkData = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("chunkData", "d")); + fieldBlockEntities = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("buffer", "c")); + fieldFull = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("blockEntitiesData", "d")); + fieldX.setAccessible(true); + fieldZ.setAccessible(true); + fieldBitMask.setAccessible(true); + fieldHeightMap.setAccessible(true); + fieldChunkData.setAccessible(true); + fieldBlockEntities.setAccessible(true); + fieldFull.setAccessible(true); + } + + @Override + public ClientboundLevelChunkWithLightPacket createPacket() { + // TODO ??? return new ClientboundLevelChunkPacket(); + throw new UnsupportedOperationException(); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightPlatformAdapter.java new file mode 100644 index 000000000..de2cf8acf --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightPlatformAdapter.java @@ -0,0 +1,717 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_3; + +import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices; +import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager; +import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; +import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; +import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.math.IntPair; +import com.fastasyncworldedit.core.util.MathMan; +import com.fastasyncworldedit.core.util.TaskManager; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +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.BlockTypesCache; +import io.papermc.lib.PaperLib; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.IdMap; +import net.minecraft.core.Registry; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.BitStorage; +import net.minecraft.util.SimpleBitStorage; +import net.minecraft.util.ThreadingDetector; +import net.minecraft.util.Unit; +import net.minecraft.util.ZeroBitStorage; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.GlobalPalette; +import net.minecraft.world.level.chunk.HashMapPalette; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.LinearPalette; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.SingleValuePalette; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import org.apache.logging.log4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.CraftChunk; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Function; + +import static java.lang.invoke.MethodType.methodType; +import static net.minecraft.core.registries.Registries.BIOME; + +public final class PaperweightPlatformAdapter extends NMSAdapter { + + public static final Field fieldData; + + public static final Constructor dataConstructor; + + public static final Field fieldStorage; + public static final Field fieldPalette; + + private static final Field fieldTickingFluidCount; + private static final Field fieldTickingBlockCount; + private static final Field fieldBiomes; + + private static final MethodHandle methodGetVisibleChunk; + + private static final Field fieldThreadingDetector; + private static final Field fieldLock; + + private static final MethodHandle methodRemoveGameEventListener; + private static final MethodHandle methodremoveTickingBlockEntity; + + /* + * This is a workaround for the changes from https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/1fddefce1cdce44010927b888432bf70c0e88cde#src/main/java/org/bukkit/craftbukkit/CraftChunk.java + * and is only needed to support 1.19.4 versions before *and* after this change. + */ + private static final MethodHandle CRAFT_CHUNK_GET_HANDLE; + + private static final Field fieldRemove; + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private static Method PAPER_CHUNK_GEN_ALL_ENTITIES; + private static Field SERVER_LEVEL_ENTITY_MANAGER; + + static final MethodHandle PALETTED_CONTAINER_GET; + + static { + final MethodHandles.Lookup lookup = MethodHandles.lookup(); + try { + fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d")); + fieldData.setAccessible(true); + + Class dataClazz = fieldData.getType(); + dataConstructor = dataClazz.getDeclaredConstructors()[0]; + dataConstructor.setAccessible(true); + + fieldStorage = dataClazz.getDeclaredField(Refraction.pickName("storage", "b")); + fieldStorage.setAccessible(true); + fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c")); + fieldPalette.setAccessible(true); + + fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "g")); + fieldTickingFluidCount.setAccessible(true); + fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); + fieldTickingBlockCount.setAccessible(true); + Field tmpFieldBiomes; + try { + // Seems it's sometimes biomes and sometimes "i". Idk this is just easier than having to try to deal with it + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); // apparently unobf + } catch (NoSuchFieldException ignored) { + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i"); // apparently obf + } + fieldBiomes = tmpFieldBiomes; + fieldBiomes.setAccessible(true); + + Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( + "getVisibleChunkIfPresent", + "b" + ), long.class); + getVisibleChunkIfPresent.setAccessible(true); + methodGetVisibleChunk = lookup.unreflect(getVisibleChunkIfPresent); + + if (!PaperLib.isPaper()) { + fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); + fieldThreadingDetector.setAccessible(true); + fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); + fieldLock.setAccessible(true); + } else { + // in paper, the used methods are synchronized properly + fieldThreadingDetector = null; + fieldLock = null; + } + + Method removeGameEventListener = LevelChunk.class.getDeclaredMethod( + Refraction.pickName("removeGameEventListener", "a"), + BlockEntity.class, + ServerLevel.class + ); + removeGameEventListener.setAccessible(true); + methodRemoveGameEventListener = lookup.unreflect(removeGameEventListener); + + Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod( + Refraction.pickName( + "removeBlockEntityTicker", + "k" + ), BlockPos.class + ); + removeBlockEntityTicker.setAccessible(true); + methodremoveTickingBlockEntity = lookup.unreflect(removeBlockEntityTicker); + + fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p")); + fieldRemove.setAccessible(true); + + try { + Level.class.getDeclaredMethod("moonrise$getEntityLookup"); + PAPER_CHUNK_GEN_ALL_ENTITIES = ChunkEntitySlices.class.getDeclaredMethod("getAllEntities"); + PAPER_CHUNK_GEN_ALL_ENTITIES.setAccessible(true); + } catch (NoSuchMethodException ignored) { + // Non-Paper + SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "N")); + SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true); + } + + Method palettedContaienrGet = PalettedContainer.class.getDeclaredMethod( + Refraction.pickName("get", "a"), + int.class + ); + palettedContaienrGet.setAccessible(true); + PALETTED_CONTAINER_GET = lookup.unreflect(palettedContaienrGet); + } catch (RuntimeException | Error e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + MethodHandle craftChunkGetHandle; + final MethodType type = methodType(LevelChunk.class); + try { + craftChunkGetHandle = lookup.findVirtual(CraftChunk.class, "getHandle", type); + } catch (NoSuchMethodException | IllegalAccessException e) { + try { + final MethodType newType = methodType(ChunkAccess.class, ChunkStatus.class); + craftChunkGetHandle = lookup.findVirtual(CraftChunk.class, "getHandle", newType); + craftChunkGetHandle = MethodHandles.insertArguments(craftChunkGetHandle, 1, ChunkStatus.FULL); + } catch (NoSuchMethodException | IllegalAccessException ex) { + throw new RuntimeException(ex); + } + } + CRAFT_CHUNK_GET_HANDLE = craftChunkGetHandle; + } + + static boolean setSectionAtomic( + String worldName, + IntPair pair, + LevelChunkSection[] sections, + LevelChunkSection expected, + LevelChunkSection value, + int layer + ) { + return NMSAdapter.setSectionAtomic(worldName, pair, sections, expected, value, layer); + } + + // There is no point in having a functional semaphore for paper servers. + private static final ThreadLocal SEMAPHORE_THREAD_LOCAL = + ThreadLocal.withInitial(() -> new DelegateSemaphore(1, null)); + + static DelegateSemaphore applyLock(LevelChunkSection section) { + if (PaperLib.isPaper()) { + return SEMAPHORE_THREAD_LOCAL.get(); + } + try { + synchronized (section) { + PalettedContainer blocks = section.getStates(); + ThreadingDetector currentThreadingDetector = (ThreadingDetector) fieldThreadingDetector.get(blocks); + synchronized (currentThreadingDetector) { + Semaphore currentLock = (Semaphore) fieldLock.get(currentThreadingDetector); + if (currentLock instanceof DelegateSemaphore delegateSemaphore) { + return delegateSemaphore; + } + DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); + fieldLock.set(currentThreadingDetector, newLock); + return newLock; + } + } + } catch (Throwable e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) { + if (!PaperLib.isPaper()) { + LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false); + if (nmsChunk != null) { + return nmsChunk; + } + if (Fawe.isMainThread()) { + return serverLevel.getChunk(chunkX, chunkZ); + } + } else { + LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ); + if (nmsChunk != null) { + addTicket(serverLevel, chunkX, chunkZ); + return nmsChunk; + } + nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ); + if (nmsChunk != null) { + addTicket(serverLevel, chunkX, chunkZ); + return nmsChunk; + } + // Avoid "async" methods from the main thread. + if (Fawe.isMainThread()) { + return serverLevel.getChunk(chunkX, chunkZ); + } + CompletableFuture future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true); + try { + CraftChunk chunk; + try { + chunk = (CraftChunk) future.get(10, TimeUnit.SECONDS); + } catch (TimeoutException e) { + String world = serverLevel.getWorld().getName(); + // We've already taken 10 seconds we can afford to wait a little here. + boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null); + if (loaded) { + LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world); + // Retry chunk load + chunk = (CraftChunk) serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true).get(); + } else { + throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!"); + } + } + addTicket(serverLevel, chunkX, chunkZ); + return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk); + } catch (Throwable e) { + e.printStackTrace(); + } + } + return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)); + } + + private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) { + // Ensure chunk is definitely loaded before applying a ticket + io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel + .getChunkSource() + .addRegionTicket(ChunkHolderManager.UNLOAD_COOLDOWN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE)); + } + + public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) { + ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap; + try { + return (ChunkHolder) methodGetVisibleChunk.invoke(chunkMap, ChunkPos.asLong(chunkX, chunkZ)); + } catch (Throwable thr) { + throw new RuntimeException(thr); + } + } + + @SuppressWarnings("deprecation") + public static void sendChunk(IntPair pair, ServerLevel nmsWorld, int chunkX, int chunkZ) { + ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); + if (chunkHolder == null) { + return; + } + ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ); + LevelChunk levelChunk; + if (PaperLib.isPaper()) { + // getChunkAtIfLoadedImmediately is paper only + levelChunk = nmsWorld.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ); + } else { + levelChunk = chunkHolder.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).orElse(null); + } + if (levelChunk == null) { + return; + } + StampLockHolder lockHolder = new StampLockHolder(); + NMSAdapter.beginChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder); + if (lockHolder.chunkLock == null) { + return; + } + MinecraftServer.getServer().execute(() -> { + try { + ClientboundLevelChunkWithLightPacket packet; + if (PaperLib.isPaper()) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); + } else { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); + } + nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); + } finally { + NMSAdapter.endChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder); + } + }); + } + + private static List nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) { + return serverLevel.getChunkSource().chunkMap.getPlayers(coordIntPair, false); + } + + /* + NMS conversion + */ + public static LevelChunkSection newChunkSection( + final int layer, + final char[] blocks, + CachedBukkitAdapter adapter, + Registry biomeRegistry, + @Nullable PalettedContainer> biomes + ) { + return newChunkSection(layer, null, blocks, adapter, biomeRegistry, biomes); + } + + public static LevelChunkSection newChunkSection( + final int layer, + final Function get, + char[] set, + CachedBukkitAdapter adapter, + Registry biomeRegistry, + @Nullable PalettedContainer> biomes + ) { + if (set == null) { + return newChunkSection(biomeRegistry, biomes); + } + final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); + final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); + final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get(); + final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get(); + try { + int num_palette; + if (get == null) { + num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter, null); + } else { + num_palette = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, get, set, adapter, null); + } + + int bitsPerEntry = MathMan.log2nlz(num_palette - 1); + if (bitsPerEntry > 0 && bitsPerEntry < 5) { + bitsPerEntry = 4; + } else if (bitsPerEntry > 8) { + bitsPerEntry = MathMan.log2nlz(Block.BLOCK_STATE_REGISTRY.size() - 1); + } + + int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes + final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); + final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong); + + if (num_palette == 1) { + for (int i = 0; i < blockBitArrayEnd; i++) { + blockStates[i] = 0; + } + } else { + final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntryNonZero, 4096, blockStates); + bitArray.fromRaw(blocksCopy); + } + + final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd); + final BitStorage nmsBits; + if (bitsPerEntry == 0) { + nmsBits = new ZeroBitStorage(4096); + } else { + nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits); + } + List palette; + if (bitsPerEntry < 9) { + palette = new ArrayList<>(); + for (int i = 0; i < num_palette; i++) { + int ordinal = paletteToBlock[i]; + blockToPalette[ordinal] = Integer.MAX_VALUE; + final BlockState state = BlockTypesCache.states[ordinal]; + palette.add(((PaperweightBlockMaterial) state.getMaterial()).getState()); + } + } else { + palette = List.of(); + } + + // Create palette with data + @SuppressWarnings("deprecation") // constructor is deprecated on paper, but needed to keep compatibility with spigot + final PalettedContainer blockStatePalettedContainer = + new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, + PalettedContainer.Strategy.SECTION_STATES, + PalettedContainer.Strategy.SECTION_STATES.getConfiguration(Block.BLOCK_STATE_REGISTRY, bitsPerEntry), + nmsBits, + palette + ); + if (biomes == null) { + IdMap> biomeHolderIdMap = biomeRegistry.asHolderIdMap(); + biomes = new PalettedContainer<>( + biomeHolderIdMap, + biomeHolderIdMap.byIdOrThrow(WorldEditPlugin + .getInstance() + .getBukkitImplAdapter() + .getInternalBiomeId( + BiomeTypes.PLAINS)), + PalettedContainer.Strategy.SECTION_BIOMES + ); + } + + return new LevelChunkSection(blockStatePalettedContainer, biomes); + } catch (final Throwable e) { + throw e; + } finally { + Arrays.fill(blockToPalette, Integer.MAX_VALUE); + Arrays.fill(paletteToBlock, Integer.MAX_VALUE); + Arrays.fill(blockStates, 0); + Arrays.fill(blocksCopy, 0); + } + } + + @SuppressWarnings("deprecation") // Only deprecated in paper + private static LevelChunkSection newChunkSection( + Registry biomeRegistry, + @Nullable PalettedContainer> biomes + ) { + if (biomes == null) { + return new LevelChunkSection(biomeRegistry); + } + PalettedContainer dataPaletteBlocks = new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), + PalettedContainer.Strategy.SECTION_STATES + ); + return new LevelChunkSection(dataPaletteBlocks, biomes); + } + + public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer> biomes) { + try { + fieldBiomes.set(section, biomes); + } catch (IllegalAccessException e) { + LOGGER.error("Could not set biomes to chunk section", e); + } + } + + /** + * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. + */ + public static PalettedContainer> getBiomePalettedContainer( + BiomeType[] biomes, + IdMap> biomeRegistry + ) { + if (biomes == null) { + return null; + } + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + // Don't stream this as typically will see 1-4 biomes; stream overhead is large for the small length + Map> palette = new HashMap<>(); + for (BiomeType biomeType : new LinkedList<>(Arrays.asList(biomes))) { + Holder biome; + if (biomeType == null) { + biome = biomeRegistry.byId(adapter.getInternalBiomeId(BiomeTypes.PLAINS)); + } else { + biome = biomeRegistry.byId(adapter.getInternalBiomeId(biomeType)); + } + palette.put(biomeType, biome); + } + int biomeCount = palette.size(); + int bitsPerEntry = MathMan.log2nlz(biomeCount - 1); + Object configuration = PalettedContainer.Strategy.SECTION_STATES.getConfiguration( + new FakeIdMapBiome(biomeCount), + bitsPerEntry + ); + if (bitsPerEntry > 3) { + bitsPerEntry = MathMan.log2nlz(biomeRegistry.size() - 1); + } + PalettedContainer> biomePalettedContainer = new PalettedContainer<>( + biomeRegistry, + biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), + PalettedContainer.Strategy.SECTION_BIOMES + ); + + final Palette> biomePalette; + if (bitsPerEntry == 0) { + biomePalette = new SingleValuePalette<>( + biomePalettedContainer.registry, + biomePalettedContainer, + new ArrayList<>(palette.values()) // Must be modifiable + ); + } else if (bitsPerEntry == 4) { + biomePalette = LinearPalette.create( + 4, + biomePalettedContainer.registry, + biomePalettedContainer, + new ArrayList<>(palette.values()) // Must be modifiable + ); + } else if (bitsPerEntry < 9) { + biomePalette = HashMapPalette.create( + bitsPerEntry, + biomePalettedContainer.registry, + biomePalettedContainer, + new ArrayList<>(palette.values()) // Must be modifiable + ); + } else { + biomePalette = GlobalPalette.create( + bitsPerEntry, + biomePalettedContainer.registry, + biomePalettedContainer, + null // unused + ); + } + + int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes + final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); + final int arrayLength = MathMan.ceilZero(64f / blocksPerLong); + + + BitStorage bitStorage = bitsPerEntry == 0 ? new ZeroBitStorage(64) : new SimpleBitStorage( + bitsPerEntry, + 64, + new long[arrayLength] + ); + + try { + Object data = dataConstructor.newInstance(configuration, bitStorage, biomePalette); + fieldData.set(biomePalettedContainer, data); + int index = 0; + for (int y = 0; y < 4; y++) { + for (int z = 0; z < 4; z++) { + for (int x = 0; x < 4; x++, index++) { + BiomeType biomeType = biomes[index]; + if (biomeType == null) { + continue; + } + Holder biome = biomeRegistry.byId(WorldEditPlugin + .getInstance() + .getBukkitImplAdapter() + .getInternalBiomeId(biomeType)); + if (biome == null) { + continue; + } + biomePalettedContainer.set(x, y, z, biome); + } + } + } + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + return biomePalettedContainer; + } + + public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException { + fieldTickingFluidCount.setShort(section, (short) 0); + fieldTickingBlockCount.setShort(section, (short) 0); + } + + public static BiomeType adapt(Holder biome, LevelAccessor levelAccessor) { + final Registry biomeRegistry = levelAccessor.registryAccess().lookupOrThrow(BIOME); + if (biomeRegistry.getKey(biome.value()) == null) { + return biomeRegistry.asHolderIdMap().getId(biome) == -1 ? BiomeTypes.OCEAN + : null; + } + return BiomeTypes.get(biome.unwrapKey().orElseThrow().location().toString()); + } + + static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { + try { + if (levelChunk.loaded || levelChunk.level.isClientSide()) { + BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos()); + if (blockEntity != null) { + if (!levelChunk.level.isClientSide) { + methodRemoveGameEventListener.invoke(levelChunk, beacon, levelChunk.level); + } + fieldRemove.set(beacon, true); + } + } + methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos()); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + + static List getEntities(LevelChunk chunk) { + if (PaperLib.isPaper()) { + try { + //noinspection unchecked + return (List) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level + .moonrise$getEntityLookup() + .getChunk(chunk.locX, chunk.locZ)); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException("Failed to lookup entities [PAPER=true]", e); + } + } + try { + //noinspection unchecked + return ((PersistentEntitySectionManager) (SERVER_LEVEL_ENTITY_MANAGER.get(chunk.level))).getEntities(chunk.getPos()); + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to lookup entities [PAPER=false]", e); + } + } + + record FakeIdMapBlock(int size) implements IdMap { + + @Override + public int getId(final net.minecraft.world.level.block.state.BlockState entry) { + return 0; + } + + @Nullable + @Override + public net.minecraft.world.level.block.state.BlockState byId(final int index) { + return null; + } + + @Nonnull + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + + } + + record FakeIdMapBiome(int size) implements IdMap { + + @Override + public int getId(final Biome entry) { + return 0; + } + + @Nullable + @Override + public Biome byId(final int index) { + return null; + } + + @Nonnull + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightPostProcessor.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightPostProcessor.java new file mode 100644 index 000000000..cbc675ecb --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightPostProcessor.java @@ -0,0 +1,175 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_3; + +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.extent.processor.ProcessorScope; +import com.fastasyncworldedit.core.queue.IBatchProcessor; +import com.fastasyncworldedit.core.queue.IChunk; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import com.fastasyncworldedit.core.registry.state.PropertyKey; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.Fluids; + +import javax.annotation.Nullable; + +public class PaperweightPostProcessor implements IBatchProcessor { + + @Override + public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) { + return set; + } + + @SuppressWarnings("deprecation") + @Override + public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) { + boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS; + // The PostProcessor shouldn't be added, but just in case + if (!tickFluid) { + return; + } + PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet; + layer: + for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) { + char[] set = iChunkSet.loadIfPresent(layer); + if (set == null) { + // No edit means no need to process + continue; + } + char[] get = null; + for (int i = 0; i < 4096; i++) { + char ordinal = set[i]; + char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__; + boolean fromGet = false; // Used for liquids + if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { + if (get == null) { + get = getBlocks.load(layer); + } + // If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't + // actually being set + if (get == null) { + continue layer; + } + fromGet = true; + ordinal = replacedOrdinal = get[i]; + } + if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { + continue; + } else if (!fromGet) { // if fromGet, don't do the same again + if (get == null) { + get = getBlocks.load(layer); + } + replacedOrdinal = get[i]; + } + boolean ticking = BlockTypesCache.ticking[ordinal]; + boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal]; + boolean replacedWasLiquid = false; + BlockState replacedState = null; + if (!ticking) { + // If the block being replaced was not ticking, it cannot be a liquid + if (!replacedWasTicking) { + continue; + } + // If the block being replaced is not fluid, we do not need to worry + if (!(replacedWasLiquid = + (replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) { + continue; + } + } + BlockState state = BlockState.getFromOrdinal(ordinal); + boolean liquid = state.getMaterial().isLiquid(); + int x = i & 15; + int y = (i >> 8) & 15; + int z = (i >> 4) & 15; + BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z); + if (liquid || replacedWasLiquid) { + if (liquid) { + addFluid(getBlocks.serverLevel, state, position); + continue; + } + // If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this + // may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up + // being ticked anyway. We only need it to be "hit" once. + if (!wasAdjacentToWater(get, set, i, x, y, z)) { + continue; + } + addFluid(getBlocks.serverLevel, replacedState, position); + } + } + } + } + + @Nullable + @Override + public Extent construct(final Extent child) { + throw new UnsupportedOperationException("Processing only"); + } + + @Override + public ProcessorScope getScope() { + return ProcessorScope.READING_SET_BLOCKS; + } + + private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) { + if (set == null || get == null) { + return false; + } + char ordinal; + char reserved = BlockTypesCache.ReservedIDs.__RESERVED__; + if (x > 0 && set[i - 1] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) { + return true; + } + } + if (x < 15 && set[i + 1] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) { + return true; + } + } + if (z > 0 && set[i - 16] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) { + return true; + } + } + if (z < 15 && set[i + 16] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) { + return true; + } + } + if (y > 0 && set[i - 256] != reserved) { + if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) { + return true; + } + } + if (y < 15 && set[i + 256] != reserved) { + return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal); + } + return false; + } + + @SuppressWarnings("deprecation") + private boolean isFluid(char ordinal) { + return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid(); + } + + @SuppressWarnings("deprecation") + private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) { + Fluid type; + if (replacedState.getBlockType() == BlockTypes.LAVA) { + type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA; + } else { + type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER; + } + serverLevel.scheduleTick( + position, + type, + type.getTickDelay(serverLevel) + ); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightStarlightRelighter.java new file mode 100644 index 000000000..0542fc641 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightStarlightRelighter.java @@ -0,0 +1,80 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_3; + +import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.math.IntPair; +import com.fastasyncworldedit.core.queue.IQueueExtent; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.TicketType; +import net.minecraft.util.Unit; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.status.ChunkPyramid; +import net.minecraft.world.level.chunk.status.ChunkStatus; + +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.IntConsumer; + +public class PaperweightStarlightRelighter extends StarlightRelighter { + + private static final TicketType FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); + private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkPyramid.LOADING_PYRAMID + .getStepTo(ChunkStatus.FULL) + .getAccumulatedRadiusOf(ChunkStatus.LIGHT); + + public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { + super(serverLevel, queue); + } + + @Override + protected ChunkPos createChunkPos(final long chunkKey) { + return new ChunkPos(chunkKey); + } + + @Override + protected long asLong(final int chunkX, final int chunkZ) { + return ChunkPos.asLong(chunkX, chunkZ); + } + + @Override + protected CompletableFuture chunkLoadFuture(final ChunkPos chunkPos) { + return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z) + .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( + FAWE_TICKET, + chunkPos, + LIGHT_LEVEL, + Unit.INSTANCE + )); + } + + protected void invokeRelight( + Set coords, + Consumer chunkCallback, + IntConsumer processCallback + ) { + try { + serverLevel.getChunkSource().getLightEngine().starlight$serverRelightChunks(coords, chunkCallback, processCallback); + } catch (Exception e) { + LOGGER.error("Error occurred on relighting", e); + } + } + + /* + * Allow the server to unload the chunks again. + * Also, if chunk packets are sent delayed, we need to do that here + */ + protected void postProcessChunks(Set coords) { + boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING; + for (ChunkPos pos : coords) { + int x = pos.x; + int z = pos.z; + if (delay) { // we still need to send the block changes of that chunk + PaperweightPlatformAdapter.sendChunk(new IntPair(x, z), serverLevel, x, z); + } + serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE); + } + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightStarlightRelighterFactory.java new file mode 100644 index 000000000..597c3a1e7 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightStarlightRelighterFactory.java @@ -0,0 +1,25 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_3; + +import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; +import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; +import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; +import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; +import com.fastasyncworldedit.core.queue.IQueueExtent; +import com.sk89q.worldedit.world.World; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.CraftWorld; + +import javax.annotation.Nonnull; + +public class PaperweightStarlightRelighterFactory implements RelighterFactory { + + @Override + public @Nonnull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { + org.bukkit.World w = Bukkit.getWorld(world.getName()); + if (w == null) { + return NullRelighter.INSTANCE; + } + return new PaperweightStarlightRelighter(((CraftWorld) w).getHandle(), queue); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/regen/PaperweightRegen.java new file mode 100644 index 000000000..bdde2bcdf --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/regen/PaperweightRegen.java @@ -0,0 +1,298 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_3.regen; + +import com.fastasyncworldedit.bukkit.adapter.Regenerator; +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.queue.IChunkCache; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.implementation.chunk.ChunkCache; +import com.google.common.collect.ImmutableList; +import com.mojang.serialization.Lifecycle; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.io.file.SafeFiles; +import com.sk89q.worldedit.world.RegenOptions; +import net.minecraft.core.Holder; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.util.ProgressListener; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelSettings; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.WorldOptions; +import net.minecraft.world.level.storage.LevelStorageSource; +import net.minecraft.world.level.storage.PrimaryLevelData; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.generator.BiomeProvider; + +import javax.annotation.Nonnull; +import java.lang.reflect.Field; +import java.nio.file.Path; +import java.util.Map; +import java.util.OptionalLong; +import java.util.function.BooleanSupplier; +import java.util.function.Supplier; + +import static net.minecraft.core.registries.Registries.BIOME; + +public class PaperweightRegen extends Regenerator { + + private static final Field serverWorldsField; + private static final Field paperConfigField; + private static final Field generatorSettingBaseSupplierField; + + + static { + try { + serverWorldsField = CraftServer.class.getDeclaredField("worlds"); + serverWorldsField.setAccessible(true); + + Field tmpPaperConfigField; + try { //only present on paper + tmpPaperConfigField = Level.class.getDeclaredField("paperConfig"); + tmpPaperConfigField.setAccessible(true); + } catch (Exception e) { + tmpPaperConfigField = null; + } + paperConfigField = tmpPaperConfigField; + + generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName( + "settings", "e")); + generatorSettingBaseSupplierField.setAccessible(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + //runtime + private ServerLevel originalServerWorld; + private ServerLevel freshWorld; + private LevelStorageSource.LevelStorageAccess session; + + private Path tempDir; + + public PaperweightRegen( + World originalBukkitWorld, + Region region, + Extent target, + RegenOptions options + ) { + super(originalBukkitWorld, region, target, options); + } + + @Override + protected void runTasks(final BooleanSupplier shouldKeepTicking) { + while (shouldKeepTicking.getAsBoolean()) { + if (!this.freshWorld.getChunkSource().pollTask()) { + return; + } + } + } + + @Override + protected boolean prepare() { + this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle(); + seed = options.getSeed().orElse(originalServerWorld.getSeed()); + return true; + } + + @Override + protected boolean initNewWorld() throws Exception { + //world folder + tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen"); + + //prepare for world init (see upstream implementation for reference) + org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment(); + org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator(); + LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir); + ResourceKey levelStemResourceKey = getWorldDimKey(environment); + session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey); + PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData; + + MinecraftServer server = originalServerWorld.getCraftServer().getServer(); + WorldOptions originalOpts = originalWorldData.worldGenOptions(); + WorldOptions newOpts = options.getSeed().isPresent() + ? originalOpts.withSeed(OptionalLong.of(seed)) + : originalOpts; + LevelSettings newWorldSettings = new LevelSettings( + "faweregentempworld", + originalWorldData.settings.gameType(), + originalWorldData.settings.hardcore(), + originalWorldData.settings.difficulty(), + originalWorldData.settings.allowCommands(), + originalWorldData.settings.gameRules(), + originalWorldData.settings.getDataConfiguration() + ); + + PrimaryLevelData.SpecialWorldProperty specialWorldProperty = + originalWorldData.isFlatWorld() + ? PrimaryLevelData.SpecialWorldProperty.FLAT + : originalWorldData.isDebugWorld() + ? PrimaryLevelData.SpecialWorldProperty.DEBUG + : PrimaryLevelData.SpecialWorldProperty.NONE; + PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable()); + + BiomeProvider biomeProvider = getBiomeProvider(); + + + //init world + freshWorld = Fawe.instance().getQueueHandler().sync((Supplier) () -> new ServerLevel( + server, + server.executor, + session, + newWorldData, + originalServerWorld.dimension(), + new LevelStem( + originalServerWorld.dimensionTypeRegistration(), + originalServerWorld.getChunkSource().getGenerator() + ), + new RegenNoOpWorldLoadListener(), + originalServerWorld.isDebug(), + seed, + ImmutableList.of(), + false, + originalServerWorld.getRandomSequences(), + environment, + generator, + biomeProvider + ) { + + private final Holder singleBiome = options.hasBiomeType() ? DedicatedServer.getServer().registryAccess() + .lookupOrThrow(BIOME).asHolderIdMap().byIdOrThrow( + WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) + ) : null; + + @Override + public @Nonnull Holder getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { + if (options.hasBiomeType()) { + return singleBiome; + } + return super.getUncachedNoiseBiome(biomeX, biomeY, biomeZ); + } + + @Override + public void save( + final ProgressListener progressListener, + final boolean flush, + final boolean savingDisabled + ) { + // noop, spigot + } + + @Override + public void save( + final ProgressListener progressListener, + final boolean flush, + final boolean savingDisabled, + final boolean close + ) { + // noop, paper + } + }).get(); + freshWorld.noSave = true; + removeWorldFromWorldsMap(); + newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name + if (paperConfigField != null) { + paperConfigField.set(freshWorld, originalServerWorld.paperConfig()); + } + return true; + } + + @Override + protected void cleanup() { + try { + session.close(); + } catch (Exception ignored) { + } + + //shutdown chunk provider + try { + Fawe.instance().getQueueHandler().sync(() -> { + try { + freshWorld.getChunkSource().getDataStorage().cache.clear(); + freshWorld.getChunkSource().close(false); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } catch (Exception ignored) { + } + + //remove world from server + try { + Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap); + } catch (Exception ignored) { + } + + //delete directory + try { + SafeFiles.tryHardToDeleteDir(tempDir); + } catch (Exception ignored) { + } + } + + @Override + protected IChunkCache initSourceQueueCache() { + return new ChunkCache<>(BukkitAdapter.adapt(freshWorld.getWorld())); + } + + //util + @SuppressWarnings("unchecked") + private void removeWorldFromWorldsMap() { + try { + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); + map.remove("faweregentempworld"); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private ResourceKey getWorldDimKey(org.bukkit.World.Environment env) { + return switch (env) { + case NETHER -> LevelStem.NETHER; + case THE_END -> LevelStem.END; + default -> LevelStem.OVERWORLD; + }; + } + + private static class RegenNoOpWorldLoadListener implements ChunkProgressListener { + + private RegenNoOpWorldLoadListener() { + } + + @Override + public void updateSpawnPos(@Nonnull ChunkPos spawnPos) { + } + + @Override + public void onStatusChange( + final @Nonnull ChunkPos pos, + @org.jetbrains.annotations.Nullable final net.minecraft.world.level.chunk.status.ChunkStatus status + ) { + + } + + @Override + public void start() { + + } + + @Override + public void stop() { + + } + + } + +} diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index 088ab22a0..c438e8ff4 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -208,7 +208,7 @@ tasks { versionNumber.set("${project.version}") versionType.set("release") uploadFile.set(file("build/libs/${rootProject.name}-Bukkit-${project.version}.jar")) - gameVersions.addAll(listOf("1.21", "1.20.6", "1.20.5", "1.20.3", "1.20.2", "1.20.1", "1.20", "1.19.4")) + gameVersions.addAll(listOf("1.20.2", "1.20.4", "1.20.6", "1.21.1", "1.21.3")) loaders.addAll(listOf("paper", "spigot")) changelog.set("The changelog is available on GitHub: https://github.com/IntellectualSites/" + "FastAsyncWorldEdit/releases/tag/${project.version}") diff --git a/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java b/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java index 507da7e01..7c871a531 100644 --- a/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java +++ b/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java @@ -20,6 +20,7 @@ package com.sk89q.wepif; import com.destroystokyo.paper.profile.PlayerProfile; +import io.papermc.paper.persistence.PersistentDataContainerView; import org.bukkit.BanEntry; import org.bukkit.Location; import org.bukkit.Material; @@ -375,4 +376,9 @@ public class TestOfflinePermissible implements OfflinePlayer, Permissible { return null; } + @Override + public @NotNull PersistentDataContainerView getPersistentDataContainer() { + throw new UnsupportedOperationException("Not supported yet."); + } + } From b09e1dbde236fc1df07ef34ddc0788806d05f918 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 01:25:21 +0000 Subject: [PATCH 438/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.4.11 (#2985) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7c9552c71..38f6d5937 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.4.9" +towny = "0.100.4.11" plotsquared = "7.3.12" # Third party From 8b18dbcdbd9397a7343c887394568829f547af46 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 01:25:50 +0000 Subject: [PATCH 439/466] Update dependency paperweight-userdev (#2986) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts | 2 +- worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts | 2 +- worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index c82a5bd55..be348efdb 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240528.102248-175") + the().paperDevBundle("1.20.4-R0.1-20241030.192207-176") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts index 1642d5a51..ffe10e3ff 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/ - the().paperDevBundle("1.20.6-R0.1-20240916.192025-125") + the().paperDevBundle("1.20.6-R0.1-20241030.191541-126") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts index a2b3da35a..8393bd1dc 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.1-R0.1-20241021.162528-124") + the().paperDevBundle("1.21.1-R0.1-20241031.174552-126") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts index 39c94c40b..90cd3f2f4 100644 --- a/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.3-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.3-R0.1-20241101.150401-13") + the().paperDevBundle("1.21.3-R0.1-20241110.003233-30") compileOnly(libs.paperlib) } From e3fc35ce6da38b457e0549af6c6a7f9d5dd0abfc Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Mon, 11 Nov 2024 21:47:29 +0100 Subject: [PATCH 440/466] Un-break for versions <1.21.3 (#2988) * Use Bukkit Registry API where possible (#2573) (cherry picked from commit 292dae65cb01929dc2158f09bdb19fdc82b3669f) * compile against 1.21 instead of 1.21.3 * remove method * Revert "Use Bukkit Registry API where possible (#2573)" This reverts commit f260e19d2976de1ceab9dc7d43a633817723f434. --------- Co-authored-by: Maddy Miller --- gradle/libs.versions.toml | 2 +- .../test/java/com/sk89q/wepif/TestOfflinePermissible.java | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 38f6d5937..ef8918c29 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] # Minecraft expectations -paper = "1.21.3-R0.1-SNAPSHOT" +paper = "1.21-R0.1-SNAPSHOT" fastutil = "8.5.9" guava = "31.1-jre" log4j = "2.19.0" diff --git a/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java b/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java index 7c871a531..9415a88f5 100644 --- a/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java +++ b/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java @@ -376,9 +376,4 @@ public class TestOfflinePermissible implements OfflinePlayer, Permissible { return null; } - @Override - public @NotNull PersistentDataContainerView getPersistentDataContainer() { - throw new UnsupportedOperationException("Not supported yet."); - } - } From dcd6b93ebb2bc68c3842ebbf5fecf2430381e753 Mon Sep 17 00:00:00 2001 From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Thu, 14 Nov 2024 09:20:53 -0700 Subject: [PATCH 441/466] Build a Mojang mapped jar in addition to the reobf one, publish both to Modrinth with correct metadata (#2981) --- .../workflows/announce-release-on-discord.yml | 2 +- .github/workflows/build-pr.yml | 2 +- .github/workflows/build.yml | 4 +- .github/workflows/upload-release-assets.yml | 2 +- buildSrc/src/main/kotlin/AdapterConfig.kt | 4 + buildSrc/src/main/kotlin/PlatformConfig.kt | 3 +- gradle/libs.versions.toml | 4 +- worldedit-bukkit/build.gradle.kts | 111 ++++++++++++++---- .../worldedit/bukkit/WorldEditPlugin.java | 48 ++++++++ .../worldedit/bukkit/adapter/Refraction.java | 4 + .../sk89q/worldedit/WorldEditManifest.java | 2 +- 11 files changed, 154 insertions(+), 32 deletions(-) diff --git a/.github/workflows/announce-release-on-discord.yml b/.github/workflows/announce-release-on-discord.yml index 77fa89732..61038e9a3 100644 --- a/.github/workflows/announce-release-on-discord.yml +++ b/.github/workflows/announce-release-on-discord.yml @@ -24,5 +24,5 @@ jobs: "" "The download is available at:" "- Spigot: " - "- Modrinth: " + "- Modrinth: " "- CurseForge: " diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index 7b578480f..8766c697b 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -24,4 +24,4 @@ jobs: uses: actions/upload-artifact@v3 with: name: FastAsyncWorldEdit-SNAPSHOT - path: worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-*.jar + path: worldedit-bukkit/build/libs/FastAsyncWorldEdit-*.jar diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 79aa448d8..a24529c9e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -70,9 +70,9 @@ jobs: uses: actions/upload-artifact@v3 with: name: FastAsyncWorldEdit-Bukkit-SNAPSHOT - path: worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-*.jar + path: worldedit-bukkit/build/libs/FastAsyncWorldEdit-*.jar - name: Publish to Modrinth if: ${{ runner.os == 'Linux' && env.STATUS == 'release' && github.event_name == 'push' && github.ref == 'refs/heads/main'}} - run: ./gradlew modrinth + run: ./gradlew publishMods env: MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} diff --git a/.github/workflows/upload-release-assets.yml b/.github/workflows/upload-release-assets.yml index c6e0ea2cf..ea012486c 100644 --- a/.github/workflows/upload-release-assets.yml +++ b/.github/workflows/upload-release-assets.yml @@ -21,6 +21,6 @@ jobs: - name: Upload Release Assets uses: AButler/upload-release-assets@v3.0 with: - files: 'worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-*.jar' + files: 'worldedit-bukkit/build/libs/FastAsyncWorldEdit-*.jar' repo-token: ${{ secrets.GITHUB_TOKEN }} release-tag: ${{ github.event.release.tag_name }} diff --git a/buildSrc/src/main/kotlin/AdapterConfig.kt b/buildSrc/src/main/kotlin/AdapterConfig.kt index 60f9a5733..1d141621b 100644 --- a/buildSrc/src/main/kotlin/AdapterConfig.kt +++ b/buildSrc/src/main/kotlin/AdapterConfig.kt @@ -20,4 +20,8 @@ fun Project.applyPaperweightAdapterConfiguration() { tasks.named("assemble") { dependsOn("reobfJar") } + + tasks.named("javadoc") { + enabled = false + } } diff --git a/buildSrc/src/main/kotlin/PlatformConfig.kt b/buildSrc/src/main/kotlin/PlatformConfig.kt index 128e7f09d..6a2c9d7ee 100644 --- a/buildSrc/src/main/kotlin/PlatformConfig.kt +++ b/buildSrc/src/main/kotlin/PlatformConfig.kt @@ -12,6 +12,7 @@ import org.gradle.kotlin.dsl.named import org.gradle.kotlin.dsl.provideDelegate import org.gradle.kotlin.dsl.register import org.gradle.kotlin.dsl.the +import org.gradle.kotlin.dsl.withType import org.gradle.plugins.signing.SigningExtension fun Project.applyPlatformAndCoreConfiguration() { @@ -132,7 +133,7 @@ fun Project.applyPlatformAndCoreConfiguration() { } fun Project.applyShadowConfiguration() { - tasks.named("shadowJar") { + tasks.withType().configureEach { dependencies { include(project(":worldedit-libs:core")) include(project(":worldedit-libs:${project.name.replace("worldedit-", "")}")) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ef8918c29..5ef81e2a6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -51,7 +51,7 @@ mockito = "5.14.2" # Gradle plugins pluginyml = "0.6.0" -minotaur = "2.8.7" +mod-publish-plugin = "0.7.4" [libraries] # Minecraft expectations @@ -127,4 +127,4 @@ log4jCore = { group = "org.apache.logging.log4j", name = "log4j-core", version.r [plugins] pluginyml = { id = "net.minecrell.plugin-yml.bukkit", version.ref = "pluginyml" } -minotaur = { id = "com.modrinth.minotaur", version.ref = "minotaur" } +mod-publish-plugin = { id = "me.modmuss50.mod-publish-plugin", version.ref = "mod-publish-plugin" } diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index c438e8ff4..8a9f43556 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -1,9 +1,10 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import io.papermc.paperweight.userdev.attribute.Obfuscation +import me.modmuss50.mpp.ReleaseType plugins { `java-library` - alias(libs.plugins.minotaur) + alias(libs.plugins.mod.publish.plugin) } project.description = "Bukkit" @@ -47,21 +48,26 @@ val localImplementation = configurations.create("localImplementation") { } val adapters = configurations.create("adapters") { - description = "Adapters to include in the JAR" + description = "Adapters to include in the JAR (Mojmap)" isCanBeConsumed = false isCanBeResolved = true shouldResolveConsistentlyWith(configurations["runtimeClasspath"]) attributes { - attribute(Obfuscation.OBFUSCATION_ATTRIBUTE, - if ((project.findProperty("enginehub.obf.none") as String?).toBoolean()) { - objects.named(Obfuscation.NONE) - } else { - objects.named(Obfuscation.OBFUSCATED) - } - ) + attribute(Obfuscation.OBFUSCATION_ATTRIBUTE, objects.named(Obfuscation.NONE)) } } +val adaptersReobf = configurations.create("adaptersReobf") { + description = "Adapters to include in the JAR (Spigot-Mapped)" + isCanBeConsumed = false + isCanBeResolved = true + shouldResolveConsistentlyWith(configurations["runtimeClasspath"]) + attributes { + attribute(Obfuscation.OBFUSCATION_ATTRIBUTE, objects.named(Obfuscation.OBFUSCATED)) + } + extendsFrom(adapters) +} + dependencies { // Modules api(projects.worldeditCore) @@ -141,9 +147,37 @@ tasks.named("jar") { addJarManifest(WorldEditKind.Plugin, includeClasspath = true) -tasks.named("shadowJar") { - configurations.add(adapters) +tasks.register("reobfShadowJar") { archiveFileName.set("${rootProject.name}-Bukkit-${project.version}.${archiveExtension.getOrElse("jar")}") + configurations = listOf( + project.configurations.runtimeClasspath.get(), // as is done by shadow for the default shadowJar + adaptersReobf + ) + + // as is done by shadow for the default shadowJar + from(sourceSets.main.map { it.output }) + manifest.inheritFrom(tasks.jar.get().manifest) + exclude("META-INF/INDEX.LIST", "META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA", "module-info.class") + + manifest { + attributes( + "FAWE-Plugin-Jar-Type" to "spigot" + ) + } +} + +tasks.named("shadowJar") { + archiveFileName.set("${rootProject.name}-Paper-${project.version}.${archiveExtension.getOrElse("jar")}") + configurations.add(adapters) + manifest { + attributes( + "paperweight-mappings-namespace" to "mojang", + "FAWE-Plugin-Jar-Type" to "mojang" + ) + } +} + +tasks.withType().configureEach { dependencies { // In tandem with not bundling log4j, we shouldn't relocate base package here. // relocate("org.apache.logging", "com.sk89q.worldedit.log4j") @@ -198,20 +232,51 @@ tasks.named("shadowJar") { tasks.named("assemble").configure { dependsOn("shadowJar") + dependsOn("reobfShadowJar") } -tasks { - modrinth { - token.set(System.getenv("MODRINTH_TOKEN")) +publishMods { + displayName.set("${project.version}") + version.set("${project.version}") + type.set(ReleaseType.STABLE) + changelog.set("The changelog is available on GitHub: https://github.com/IntellectualSites/" + + "FastAsyncWorldEdit/releases/tag/${project.version}") + + val common = modrinthOptions { + accessToken.set(System.getenv("MODRINTH_TOKEN")) projectId.set("fastasyncworldedit") - versionName.set("${project.version}") - versionNumber.set("${project.version}") - versionType.set("release") - uploadFile.set(file("build/libs/${rootProject.name}-Bukkit-${project.version}.jar")) - gameVersions.addAll(listOf("1.20.2", "1.20.4", "1.20.6", "1.21.1", "1.21.3")) - loaders.addAll(listOf("paper", "spigot")) - changelog.set("The changelog is available on GitHub: https://github.com/IntellectualSites/" + - "FastAsyncWorldEdit/releases/tag/${project.version}") - syncBodyFrom.set(rootProject.file("README.md").readText()) + projectDescription.set(rootProject.file("README.md").readText()) } + + // We publish the reobfJar twice to ensure that the modrinth download menu picks the right jar for the platform regardless + // of minecraft version. + + val mojmapPaperVersions = listOf("1.20.6", "1.21.1", "1.21.3") + val spigotMappedPaperVersions = listOf("1.20.2", "1.20.4") + + // Mark reobfJar as spigot only for 1.20.5+ + modrinth("spigot") { + from(common) + file.set(tasks.named("reobfShadowJar").flatMap { it.archiveFile }) + minecraftVersions.set(mojmapPaperVersions) + modLoaders.set(listOf("spigot")) + } + + // Mark reobfJar as spigot & paper for <1.20.5 + modrinth("spigotAndOldPaper") { + from(common) + file.set(tasks.named("reobfShadowJar").flatMap { it.archiveFile }) + minecraftVersions.set(spigotMappedPaperVersions) + modLoaders.set(listOf("paper", "spigot")) + } + + // Mark mojang mapped jar as paper 1.20.5+ only + modrinth { + from(common) + file.set(tasks.named("shadowJar").flatMap { it.archiveFile }) + minecraftVersions.set(mojmapPaperVersions) + modLoaders.set(listOf("paper")) + } + + // dryRun.set(true) // For testing } 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 f676ae07b..c11f8bd73 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 @@ -32,9 +32,11 @@ import com.sk89q.wepif.PermissionsResolverManager; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditManifest; import com.sk89q.worldedit.bukkit.adapter.AdapterLoadException; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplLoader; +import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.event.platform.CommandEvent; import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; import com.sk89q.worldedit.event.platform.PlatformReadyEvent; @@ -90,7 +92,9 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import java.util.Locale; +import java.util.Objects; import java.util.Optional; +import java.util.jar.Attributes; import static com.google.common.base.Preconditions.checkNotNull; import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME; @@ -131,6 +135,50 @@ public class WorldEditPlugin extends JavaPlugin { } } //FAWE end + //FAWE start + final Attributes attributes = WorldEditManifest.readAttributes(); + Objects.requireNonNull(attributes, "Could not retrieve manifest attributes"); + final String type = attributes.getValue("FAWE-Plugin-Jar-Type"); + Objects.requireNonNull(type, "Could not determine plugin jar type"); + if (PaperLib.isPaper()) { + if (PaperLib.getMinecraftVersion() < 20 || (PaperLib.getMinecraftVersion() == 20 && PaperLib.getMinecraftPatchVersion() < 5)) { + if (type.equals("mojang") && !Refraction.isMojangMapped()) { + throw new IllegalStateException( + """ + + ********************************************** + ** You are using the wrong FAWE jar for your Minecraft version. + ** Download the correct FAWE jar from Modrinth: https://modrinth.com/plugin/fastasyncworldedit/ + **********************************************""" + ); + } + } else if (PaperLib.getMinecraftVersion() > 20 || (PaperLib.getMinecraftVersion() == 20 && PaperLib.getMinecraftPatchVersion() >= 5)) { + if (type.equals("spigot")) { + LOGGER.warn( + """ + + ********************************************** + ** You are using the Spigot-mapped FAWE jar on a modern Paper version. + ** This will result in slower first-run times and wasted disk space from plugin remapping. + ** Download the Paper FAWE jar from Modrinth to avoid this: https://modrinth.com/plugin/fastasyncworldedit/ + **********************************************""" + ); + } + } + } else { + if (type.equals("mojang")) { + throw new IllegalStateException( + """ + + ********************************************** + ** You are attempting to run the Paper FAWE jar on a Spigot server. + ** Either switch to Paper (https://papermc.io), or download the correct FAWE jar for your platform + ** from Modrinth: https://modrinth.com/plugin/fastasyncworldedit/ + **********************************************""" + ); + } + } + //FAWE end INSTANCE = this; diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/Refraction.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/Refraction.java index 025700ace..273853186 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/Refraction.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/Refraction.java @@ -42,6 +42,10 @@ public class Refraction { return IS_MOJANG_MAPPED ? mojangName : spigotName; } + public static boolean isMojangMapped() { + return IS_MOJANG_MAPPED; + } + private Refraction() { } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEditManifest.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEditManifest.java index 449e08db3..c7ffa7769 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEditManifest.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEditManifest.java @@ -64,7 +64,7 @@ public class WorldEditManifest { } @Nullable - private static Attributes readAttributes() { + public static Attributes readAttributes() { Class clazz = WorldEditManifest.class; String className = clazz.getSimpleName() + ".class"; String classPath = clazz.getResource(className).toString(); From 7a020f436a3ae06abc2d25aa33781689917be16b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 02:04:54 +0000 Subject: [PATCH 442/466] Update dependency paperweight-userdev to v1.21.3-R0.1-20241117.183222-36 (#2996) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts index 90cd3f2f4..0e487c39b 100644 --- a/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.3-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.3-R0.1-20241110.003233-30") + the().paperDevBundle("1.21.3-R0.1-20241117.183222-36") compileOnly(libs.paperlib) } From b198a750113b3df63e76ed26e994b2234cb30f43 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 02:05:13 +0000 Subject: [PATCH 443/466] Update dependency com.palmergames.bukkit.towny:towny to v0.100.4.13 (#2995) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5ef81e2a6..3226fbc23 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.4.11" +towny = "0.100.4.13" plotsquared = "7.3.12" # Third party From d52e5b0970d96f00b0909d9b8039d06ada6714c3 Mon Sep 17 00:00:00 2001 From: Jordan Date: Tue, 19 Nov 2024 15:54:49 +0000 Subject: [PATCH 444/466] fix: correctly check for properties in thaw/snow (#2976) --- .../java/com/sk89q/worldedit/EditSession.java | 2 +- .../function/block/SnowSimulator.java | 24 +++++++++---------- .../registry/state/AbstractProperty.java | 4 ++-- .../worldedit/world/block/BlockState.java | 2 +- .../worldedit/world/block/BlockType.java | 14 ++++------- 5 files changed, 20 insertions(+), 26 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 95bffb681..7986ee366 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -2788,7 +2788,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { if (setBlock(mutable, air)) { if (y > getMinY()) { BlockState block = getBlock(mutable2); - if (block.getStates().containsKey(snowy)) { + if (block.getBlockType().hasProperty(snowy)) { if (setBlock(mutable2, block.with(snowy, false))) { affected++; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/SnowSimulator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/SnowSimulator.java index 962fb3c7d..e64bb69bb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/SnowSimulator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/SnowSimulator.java @@ -26,11 +26,12 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.BooleanProperty; import com.sk89q.worldedit.registry.state.EnumProperty; import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.block.BlockCategories; import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import java.util.Locale; -import java.util.Map; public class SnowSimulator implements LayerFunction { @@ -120,22 +121,19 @@ public class SnowSimulator implements LayerFunction { abovePosition) > 10) { return false; } else if (!block.getBlockType().getMaterial().isFullCube()) { - Map, Object> states = block.getStates(); - if (states.containsKey(slab) && block.getState(slab).equalsIgnoreCase("bottom")) { + BlockType type = block.getBlockType(); + if (type.hasProperty(slab) && block.getState(slab).equalsIgnoreCase("bottom")) { return false; - } else if (states.containsKey(trapdoorOpen) && states.containsKey(trapdoor) && (block.getState(trapdoorOpen) - || block.getState(trapdoor).equalsIgnoreCase("bottom"))) { + } else if ((type.hasProperty(trapdoorOpen) && block.getState(trapdoorOpen)) || + (type.hasProperty(trapdoor) && block.getState(trapdoor).equalsIgnoreCase("bottom"))) { return false; - } else if (states.containsKey(stair) && block.getState(stair).equalsIgnoreCase("bottom")) { + } else if (type.hasProperty(stair) && block.getState(stair).equalsIgnoreCase("bottom")) { return false; } else { return false; } //FAWE end - } else if (!block.getBlockType().id().toLowerCase(Locale.ROOT).contains("ice") && block - .getBlockType() - .getMaterial() - .isTranslucent()) { + } else if (!BlockCategories.SNOW_LAYER_CAN_SURVIVE_ON.contains(block.getBlockType())) { return false; } @@ -144,14 +142,14 @@ public class SnowSimulator implements LayerFunction { // We've hit the highest layer (If it doesn't contain current + 2 it means it's 1 away from full) if (!snowLayersProperty.getValues().contains(currentHeight + 2)) { if (this.extent.setBlock(abovePosition, snowBlock)) { - if (block.getStates().containsKey(snowy)) { + if (block.getBlockType().hasProperty(snowy)) { this.extent.setBlock(position, block.with(snowy, true)); } this.affected++; } } else { if (this.extent.setBlock(abovePosition, above.with(snowLayersProperty, currentHeight + 1))) { - if (block.getStates().containsKey(snowy)) { + if (block.getBlockType().hasProperty(snowy)) { this.extent.setBlock(position, block.with(snowy, true)); } this.affected++; @@ -160,7 +158,7 @@ public class SnowSimulator implements LayerFunction { return false; } if (this.extent.setBlock(abovePosition, snow)) { - if (block.getStates().containsKey(snowy)) { + if (block.getBlockType().hasProperty(snowy)) { this.extent.setBlock(position, block.with(snowy, true)); } this.affected++; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/state/AbstractProperty.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/state/AbstractProperty.java index e248ad5cb..423e47263 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/state/AbstractProperty.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/state/AbstractProperty.java @@ -140,10 +140,10 @@ public abstract class AbstractProperty implements Property { @Override public boolean equals(Object obj) { - if (!(obj instanceof Property)) { + if (!(obj instanceof Property property)) { return false; } - return getName().equals(((Property) obj).getName()); + return getName().equals(property.getName()) && property.getValues().equals(getValues()); } //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index b6a12cb7c..0be6d43c8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -366,7 +366,7 @@ public class BlockState implements BlockStateHolder, Pattern { BlockState newState = this; for (Property prop : ot.getProperties()) { PropertyKey key = prop.getKey(); - if (blockType.hasPropertyOfType(key, prop.getClass())) { + if (blockType.hasProperty(prop)) { newState = newState.with(key, other.getState(key)); } } 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 e72d0b0e3..eb53032b2 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 @@ -248,18 +248,14 @@ public class BlockType implements Keyed, Pattern { } /** - * {@return whether this block type has a property with given key of the given type} + * {@return whether this block type has a given property} * - * @param key the key identifying the property - * @param propertyType the expected type of the property + * @param property the expected property * @since TODO */ - public boolean hasPropertyOfType(PropertyKey key, Class propertyType) { - int ordinal = key.getId(); - Property property; - return this.settings.propertiesMapArr.length > ordinal - && (property = this.settings.propertiesMapArr[ordinal]) != null - && property.getClass() == propertyType; + public boolean hasProperty(Property property) { + int ordinal = property.getKey().getId(); + return this.settings.propertiesMapArr.length > ordinal && property.equals(this.settings.propertiesMapArr[ordinal]); } public Property getProperty(PropertyKey key) { From a99c39889f391a6ed8895efc43279be321d4699b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 19 Nov 2024 16:08:39 +0000 Subject: [PATCH 445/466] Update dependency gradle to v8.11 (#3002) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index df97d72b8..94113f200 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 02349bcfdfa87490faa4b585bc1194560073ed1c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 19 Nov 2024 16:08:55 +0000 Subject: [PATCH 446/466] Update dependency me.modmuss50.mod-publish-plugin to v0.8.0 (#3003) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3226fbc23..c3112c66a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -51,7 +51,7 @@ mockito = "5.14.2" # Gradle plugins pluginyml = "0.6.0" -mod-publish-plugin = "0.7.4" +mod-publish-plugin = "0.8.0" [libraries] # Minecraft expectations From 059df70c7956e9aa673bda6c68deeb10368a5752 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 19 Nov 2024 16:16:36 +0000 Subject: [PATCH 447/466] Update dependency io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin to v1.7.5 (#3000) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 670f38b88..a7b6d53d7 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -24,7 +24,7 @@ dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:5.3.0") implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.5") - implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.4") + implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.5") constraints { val asmVersion = "[9.7,)" implementation("org.ow2.asm:asm:$asmVersion") { From 1cad61c4c4b1e9337a1e2e24977e309b137dd15a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 19 Nov 2024 16:18:29 +0000 Subject: [PATCH 448/466] Update dependency paperweight-userdev to v1.21.3-R0.1-20241119.112919-49 (#3001) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts index 0e487c39b..b647fa0a8 100644 --- a/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.3-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.3-R0.1-20241117.183222-36") + the().paperDevBundle("1.21.3-R0.1-20241119.112919-49") compileOnly(libs.paperlib) } From 28fb77eb20335e31f14f09093c231465bd180f46 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Tue, 19 Nov 2024 17:51:43 +0100 Subject: [PATCH 449/466] Release 2.12.1 Signed-off-by: Alexander Brandes --- build.gradle.kts | 2 +- .../src/main/java/com/fastasyncworldedit/core/Fawe.java | 8 ++++---- .../java/com/sk89q/worldedit/world/block/BlockType.java | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index aa979af3f..f8b90d3d5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s-%s", rootVersion, buildNumber) +version = String.format("%s", rootVersion) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java index 6238ea1ea..f20482f23 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java @@ -469,7 +469,7 @@ public class Fawe { * {@link Fawe#submitUUIDKeyQueuedTask(UUID, Runnable, Object), {@link Fawe#submitUUIDKeyQueuedTask(UUID, Callable)} * to ensure if a thread is already a UUID-queued thread, the task is immediately run */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.12.1") public KeyQueuedExecutorService getClipboardExecutor() { return this.uuidKeyQueuedExecutorService; } @@ -478,7 +478,7 @@ public class Fawe { * Submit a task to the UUID key-queued executor * * @return Future representing the tank - * @since TODO + * @since 2.12.1 */ public Future submitUUIDKeyQueuedTask(UUID uuid, Runnable runnable) { if (Thread.currentThread() instanceof UUIDKeyQueuedThreadFactory.UUIDKeyQueuedThread) { @@ -492,7 +492,7 @@ public class Fawe { * Submit a task to the UUID key-queued executor * * @return Future representing the tank - * @since TODO + * @since 2.12.1 */ public Future submitUUIDKeyQueuedTask(UUID uuid, Runnable runnable, T result) { if (Thread.currentThread() instanceof UUIDKeyQueuedThreadFactory.UUIDKeyQueuedThread) { @@ -506,7 +506,7 @@ public class Fawe { * Submit a task to the UUID key-queued executor * * @return Future representing the tank - * @since TODO + * @since 2.12.1 */ public Future submitUUIDKeyQueuedTask(UUID uuid, Callable callable) { if (Thread.currentThread() instanceof UUIDKeyQueuedThreadFactory.UUIDKeyQueuedThread) { 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 eb53032b2..4592c7ce2 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 @@ -251,7 +251,7 @@ public class BlockType implements Keyed, Pattern { * {@return whether this block type has a given property} * * @param property the expected property - * @since TODO + * @since 2.12.1 */ public boolean hasProperty(Property property) { int ordinal = property.getKey().getId(); From 308e909dea8a6fee08bfef283cf4172d99b7d09e Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Tue, 19 Nov 2024 17:57:08 +0100 Subject: [PATCH 450/466] Back to snapshot for development Signed-off-by: Alexander Brandes --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index f8b90d3d5..02cdc2f03 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.12.1") +var rootVersion by extra("2.12.2") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s", rootVersion) +version = String.format("%s-%s", rootVersion, buildNumber) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From 215898158f1a36bf9f9ac78cb1f9a16802deb5cf Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sat, 23 Nov 2024 18:55:04 +0100 Subject: [PATCH 451/466] Synchronize bundled data with WE (#2999) --- .../sk89q/worldedit/internal/Constants.java | 16 +++++++--- .../world/registry/BundledItemData.java | 31 ++----------------- .../world/registry/BundledRegistries.java | 6 ++-- .../worldedit/world/registry/blocks.115.json | 1 - .../worldedit/world/registry/blocks.116.json | 1 - .../worldedit/world/registry/blocks.117.json | 1 - .../worldedit/world/registry/blocks.119.json | 1 - .../worldedit/world/registry/blocks.121.json | 1 + .../worldedit/world/registry/blocks.1213.json | 1 + .../worldedit/world/registry/items.115.json | 1 - .../worldedit/world/registry/items.116.json | 1 - .../worldedit/world/registry/items.117.json | 1 - .../worldedit/world/registry/items.119.json | 1 - .../worldedit/world/registry/items.121.json | 1 + .../worldedit/world/registry/items.1213.json | 1 + 15 files changed, 21 insertions(+), 44 deletions(-) delete mode 100644 worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.115.json delete mode 100644 worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.116.json delete mode 100644 worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.117.json delete mode 100644 worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.119.json create mode 100644 worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.121.json create mode 100644 worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.1213.json delete mode 100644 worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.115.json delete mode 100644 worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.116.json delete mode 100644 worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.117.json delete mode 100644 worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.119.json create mode 100644 worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.121.json create mode 100644 worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.1213.json diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/Constants.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/Constants.java index 0cdd9e8dc..999d646ac 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/Constants.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/Constants.java @@ -19,8 +19,6 @@ package com.sk89q.worldedit.internal; -import java.util.Arrays; -import java.util.Collections; import java.util.List; public final class Constants { @@ -35,11 +33,11 @@ public final class Constants { public static final List NO_COPY_ENTITY_NBT_FIELDS; static { - NO_COPY_ENTITY_NBT_FIELDS = Collections.unmodifiableList(Arrays.asList( + NO_COPY_ENTITY_NBT_FIELDS = List.of( "UUIDLeast", "UUIDMost", "UUID", // Bukkit and Vanilla "WorldUUIDLeast", "WorldUUIDMost", // Bukkit and Vanilla "PersistentIDMSB", "PersistentIDLSB" // Forge - )); + ); } /** @@ -86,4 +84,14 @@ public final class Constants { */ public static final int DATA_VERSION_MC_1_20 = 3463; + /** + * The DataVersion for Minecraft 1.21 + */ + public static final int DATA_VERSION_MC_1_21 = 3953; + + /** + * The DataVersion for Minecraft 1.21.3 + */ + public static final int DATA_VERSION_MC_1_21_3 = 4082; + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java index 80a1e5e5b..126a0a967 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java @@ -55,7 +55,6 @@ public final class BundledItemData { private static final Logger LOGGER = LogManagerCompat.getLogger(); private static BundledItemData INSTANCE; - private final ResourceLoader resourceLoader; private final Map idMap = new HashMap<>(); @@ -63,12 +62,6 @@ public final class BundledItemData { * Create a new instance. */ private BundledItemData() { - this.resourceLoader = WorldEdit - .getInstance() - .getPlatformManager() - .queryCapability(Capability.CONFIGURATION) - .getResourceLoader(); - try { loadFromResource(); } catch (Throwable e) { @@ -85,28 +78,10 @@ public final class BundledItemData { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter()); Gson gson = gsonBuilder.create(); - URL url = null; - final int dataVersion = WorldEdit - .getInstance() - .getPlatformManager() - .queryCapability(Capability.WORLD_EDITING) - .getDataVersion(); - if (dataVersion >= Constants.DATA_VERSION_MC_1_17) { - url = resourceLoader.getResource(BundledBlockData.class, "items.117.json"); - } else if (dataVersion >= Constants.DATA_VERSION_MC_1_16) { - url = resourceLoader.getResource(BundledBlockData.class, "items.116.json"); - } else if (dataVersion >= Constants.DATA_VERSION_MC_1_15) { - url = resourceLoader.getResource(BundledBlockData.class, "items.115.json"); - } - if (url == null) { - url = resourceLoader.getResource(BundledBlockData.class, "items.json"); - } - if (url == null) { - throw new IOException("Could not find items.json"); - } + URL url = BundledRegistries.loadRegistry("items"); + LOGGER.debug("Using {} for bundled item data.", url); String data = Resources.toString(url, Charset.defaultCharset()); - List entries = gson.fromJson(data, new TypeToken>() { - }.getType()); + List entries = gson.fromJson(data, new TypeToken>() {}.getType()); for (ItemEntry entry : entries) { idMap.put(entry.id, entry); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledRegistries.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledRegistries.java index 26113dd6e..945801ee9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledRegistries.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledRegistries.java @@ -43,11 +43,9 @@ public class BundledRegistries implements Registries { static { TreeRangeMap versionMap = TreeRangeMap.create(); - versionMap.put(Range.atLeast(Constants.DATA_VERSION_MC_1_16), "116"); - versionMap.put(Range.atLeast(Constants.DATA_VERSION_MC_1_17), "117"); - // 1.18 did have one item change, but we didn't get it. It's fine. - versionMap.put(Range.atLeast(Constants.DATA_VERSION_MC_1_19), "119"); versionMap.put(Range.atLeast(Constants.DATA_VERSION_MC_1_20), "120"); + versionMap.put(Range.atLeast(Constants.DATA_VERSION_MC_1_21), "121"); + versionMap.put(Range.atLeast(Constants.DATA_VERSION_MC_1_21_3), "1213"); VERSION_MAP = ImmutableRangeMap.copyOf(versionMap); } diff --git a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.115.json b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.115.json deleted file mode 100644 index a08b75364..000000000 --- a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.115.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":"minecraft:acacia_button","localizedName":"Acacia Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_wall_sign","localizedName":"Acacia Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","material":{"powerSource":false,"lightValue":0,"hardness":0.7,"resistance":0.7,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:air","localizedName":"Air","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:allium","localizedName":"Allium","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:andesite","localizedName":"Andesite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:anvil","localizedName":"Anvil","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":1200,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:attached_melon_stem","localizedName":"Attached Melon Stem","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:attached_pumpkin_stem","localizedName":"Attached Pumpkin Stem","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bamboo","localizedName":"Bamboo","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bamboo_sapling","localizedName":"Bamboo Sapling","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":false,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:barrel","localizedName":"Barrel","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:barrier","localizedName":"Barrier","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:beacon","localizedName":"Beacon","material":{"powerSource":false,"lightValue":15,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bedrock","localizedName":"Bedrock","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:beehive","localizedName":"Beehive","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:beetroots","localizedName":"Beetroots","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bell","localizedName":"Bell","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_button","localizedName":"Birch Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_door","localizedName":"Birch Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_log","localizedName":"Birch Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_wall_sign","localizedName":"Birch Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_banner","localizedName":"Black Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_bed","localizedName":"Black Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_wall_banner","localizedName":"Black Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:black_wool","localizedName":"Black Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","material":{"powerSource":false,"lightValue":0,"hardness":2.8,"resistance":2.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.989,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a0a0ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_wall_banner","localizedName":"Blue Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bone_block","localizedName":"Bone Block","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":1.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brain_coral_wall_fan","localizedName":"Brain Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","material":{"powerSource":false,"lightValue":1,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bricks","localizedName":"Bricks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","material":{"powerSource":false,"lightValue":1,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_wall_banner","localizedName":"Brown Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_column","localizedName":"Bubble Column","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":true,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:bubble_coral_wall_fan","localizedName":"Bubble Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cactus","localizedName":"Cactus","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cake","localizedName":"Cake","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:campfire","localizedName":"Campfire","material":{"powerSource":false,"lightValue":15,"hardness":2,"resistance":2,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:carrots","localizedName":"Carrots","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cauldron","localizedName":"Cauldron","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cave_air","localizedName":"Cave Air","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chest","localizedName":"Chest","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":1200,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:clay","localizedName":"Clay","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:coal_block","localizedName":"Block of Coal","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cobweb","localizedName":"Cobweb","material":{"powerSource":false,"lightValue":0,"hardness":4,"resistance":4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cocoa","localizedName":"Cocoa","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":3,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:command_block","localizedName":"Command Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","material":{"powerSource":true,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:composter","localizedName":"Composter","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:conduit","localizedName":"Conduit","material":{"powerSource":false,"lightValue":15,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cornflower","localizedName":"Cornflower","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:creeper_wall_head","localizedName":"Creeper Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_wall_banner","localizedName":"Cyan Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":1200,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dandelion","localizedName":"Dandelion","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_wall_sign","localizedName":"Dark Oak Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","material":{"powerSource":true,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_brain_coral_wall_fan","localizedName":"Dead Brain Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bubble_coral_wall_fan","localizedName":"Dead Bubble Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_fire_coral_wall_fan","localizedName":"Dead Fire Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_horn_coral_wall_fan","localizedName":"Dead Horn Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dead_tube_coral_wall_fan","localizedName":"Dead Tube Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","material":{"powerSource":true,"lightValue":0,"hardness":0.7,"resistance":0.7,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diorite","localizedName":"Diorite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dirt","localizedName":"Dirt","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dispenser","localizedName":"Dispenser","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","material":{"powerSource":false,"lightValue":1,"hardness":3,"resistance":9,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dragon_wall_head","localizedName":"Dragon Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:dropper","localizedName":"Dropper","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":1200,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_gateway","localizedName":"End Gateway","material":{"powerSource":false,"lightValue":15,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_portal","localizedName":"End Portal","material":{"powerSource":false,"lightValue":15,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","material":{"powerSource":false,"lightValue":1,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_rod","localizedName":"End Rod","material":{"powerSource":false,"lightValue":14,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_stone","localizedName":"End Stone","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":9,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":9,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":9,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":9,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":9,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","material":{"powerSource":false,"lightValue":7,"hardness":22.5,"resistance":600,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:farmland","localizedName":"Farmland","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fern","localizedName":"Fern","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire","localizedName":"Fire","material":{"powerSource":false,"lightValue":15,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fire_coral_wall_fan","localizedName":"Fire Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:frosted_ice","localizedName":"Frosted Ice","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":true,"slipperiness":0.98,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a0a0ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:furnace","localizedName":"Furnace","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:glass","localizedName":"Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:glowstone","localizedName":"Glowstone","material":{"powerSource":false,"lightValue":15,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gold_block","localizedName":"Block of Gold","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:granite","localizedName":"Granite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:grass","localizedName":"Grass","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:grass_block","localizedName":"Grass Block","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:grass_path","localizedName":"Grass Path","material":{"powerSource":false,"lightValue":0,"hardness":0.65,"resistance":0.65,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gravel","localizedName":"Gravel","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_wall_banner","localizedName":"Gray Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_banner","localizedName":"Green Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_bed","localizedName":"Green Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_wall_banner","localizedName":"Green Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:green_wool","localizedName":"Green Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:grindstone","localizedName":"Grindstone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:hay_block","localizedName":"Hay Bale","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:honey_block","localizedName":"Honey Block","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:hopper","localizedName":"Hopper","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":4.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:horn_coral_wall_fan","localizedName":"Horn Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:ice","localizedName":"Ice","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":true,"slipperiness":0.98,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a0a0ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0.75,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_block","localizedName":"Block of Iron","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_door","localizedName":"Iron Door","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o'Lantern","material":{"powerSource":false,"lightValue":15,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jukebox","localizedName":"Jukebox","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_wall_sign","localizedName":"Jungle Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:kelp","localizedName":"Kelp","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:kelp_plant","localizedName":"Kelp Plant","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:ladder","localizedName":"Ladder","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lantern","localizedName":"Lantern","material":{"powerSource":false,"lightValue":15,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lapis_block","localizedName":"Lapis Lazuli Block","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:large_fern","localizedName":"Large Fern","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lava","localizedName":"Lava","material":{"powerSource":false,"lightValue":15,"hardness":100,"resistance":100,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":true,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#ff0000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lectern","localizedName":"Lectern","material":{"powerSource":true,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:lever","localizedName":"Lever","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_wall_banner","localizedName":"Light Blue Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_wall_banner","localizedName":"Light Gray Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lilac","localizedName":"Lilac","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_wall_banner","localizedName":"Lime Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:loom","localizedName":"Loom","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_wall_banner","localizedName":"Magenta Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:magma_block","localizedName":"Magma Block","material":{"powerSource":false,"lightValue":3,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:melon","localizedName":"Melon","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:melon_stem","localizedName":"Melon Stem","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:moving_piston","localizedName":"Moving Piston","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#707070","isTranslucent":true,"hasContainer":false}},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:mycelium","localizedName":"Mycelium","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_portal","localizedName":"Nether Portal","material":{"powerSource":false,"lightValue":11,"hardness":-1,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7fb238","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:netherrack","localizedName":"Netherrack","material":{"powerSource":false,"lightValue":0,"hardness":0.4,"resistance":0.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:note_block","localizedName":"Note Block","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_button","localizedName":"Oak Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_door","localizedName":"Oak Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_log","localizedName":"Oak Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_wall_sign","localizedName":"Oak Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:observer","localizedName":"Observer","material":{"powerSource":true,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:obsidian","localizedName":"Obsidian","material":{"powerSource":false,"lightValue":0,"hardness":50,"resistance":1200,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_wall_banner","localizedName":"Orange Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.98,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a0a0ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:peony","localizedName":"Peony","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_wall_banner","localizedName":"Pink Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:piston","localizedName":"Piston","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:piston_head","localizedName":"Piston Head","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:player_head","localizedName":"Player Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:player_wall_head","localizedName":"Player Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:podzol","localizedName":"Podzol","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#976d4d","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:poppy","localizedName":"Poppy","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potatoes","localizedName":"Potatoes","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_acacia_sapling","localizedName":"Potted Acacia Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_allium","localizedName":"Potted Allium","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_azure_bluet","localizedName":"Potted Azure Bluet","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_bamboo","localizedName":"Potted Bamboo","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_birch_sapling","localizedName":"Potted Birch Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_blue_orchid","localizedName":"Potted Blue Orchid","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_brown_mushroom","localizedName":"Potted Brown Mushroom","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_cactus","localizedName":"Potted Cactus","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_cornflower","localizedName":"Potted Cornflower","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_dandelion","localizedName":"Potted Dandelion","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_dark_oak_sapling","localizedName":"Potted Dark Oak Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_dead_bush","localizedName":"Potted Dead Bush","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_fern","localizedName":"Potted Fern","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_jungle_sapling","localizedName":"Potted Jungle Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_lily_of_the_valley","localizedName":"Potted Lily of the Valley","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_oak_sapling","localizedName":"Potted Oak Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_orange_tulip","localizedName":"Potted Orange Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_oxeye_daisy","localizedName":"Potted Oxeye Daisy","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_pink_tulip","localizedName":"Potted Pink Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_poppy","localizedName":"Potted Poppy","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_red_mushroom","localizedName":"Potted Red Mushroom","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_red_tulip","localizedName":"Potted Red Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_spruce_sapling","localizedName":"Potted Spruce Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_white_tulip","localizedName":"Potted White Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:potted_wither_rose","localizedName":"Potted Wither Rose","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","material":{"powerSource":false,"lightValue":0,"hardness":0.7,"resistance":0.7,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine","localizedName":"Prismarine","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:pumpkin_stem","localizedName":"Pumpkin Stem","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_wall_banner","localizedName":"Purple Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:rail","localizedName":"Rail","material":{"powerSource":false,"lightValue":0,"hardness":0.7,"resistance":0.7,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_banner","localizedName":"Red Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_bed","localizedName":"Red Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sand","localizedName":"Red Sand","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_wall_banner","localizedName":"Red Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:red_wool","localizedName":"Red Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","material":{"powerSource":true,"lightValue":0,"hardness":5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","material":{"powerSource":true,"lightValue":7,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_wall_torch","localizedName":"Redstone Torch","material":{"powerSource":true,"lightValue":7,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:redstone_wire","localizedName":"Redstone Wire","material":{"powerSource":true,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","material":{"powerSource":true,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sand","localizedName":"Sand","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sandstone","localizedName":"Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":true,"hasContainer":false}},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","material":{"powerSource":false,"lightValue":15,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","material":{"powerSource":false,"lightValue":6,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:seagrass","localizedName":"Seagrass","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:skeleton_wall_skull","localizedName":"Skeleton Skull","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:slime_block","localizedName":"Slime Block","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.8,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a4a8b8","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","material":{"powerSource":false,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smoker","localizedName":"Smoker","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:snow","localizedName":"Snow","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":true,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#ffffff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:snow_block","localizedName":"Snow Block","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#ffffff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spawner","localizedName":"Spawner","material":{"powerSource":false,"lightValue":0,"hardness":5,"resistance":5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sponge","localizedName":"Sponge","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#e5e533","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","material":{"powerSource":false,"lightValue":0,"hardness":3,"resistance":3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_wall_sign","localizedName":"Spruce Sign","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":true,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone","localizedName":"Stone","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_button","localizedName":"Stone Button","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","material":{"powerSource":true,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":6,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","material":{"powerSource":false,"lightValue":0,"hardness":3.5,"resistance":3.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:structure_block","localizedName":"Structure Block","material":{"powerSource":false,"lightValue":0,"hardness":-1,"resistance":3600000,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#a7a7a7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:structure_void","localizedName":"Structure Void","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sunflower","localizedName":"Sunflower","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:sweet_berry_bush","localizedName":"Sweet Berry Bush","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tall_seagrass","localizedName":"Tall Seagrass","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:terracotta","localizedName":"Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tnt","localizedName":"TNT","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#ff0000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:torch","localizedName":"Torch","material":{"powerSource":false,"lightValue":14,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","material":{"powerSource":true,"lightValue":0,"hardness":2.5,"resistance":2.5,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":true}},{"id":"minecraft:tripwire","localizedName":"Tripwire","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","material":{"powerSource":true,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","material":{"powerSource":false,"lightValue":0,"hardness":1.5,"resistance":6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:tube_coral_wall_fan","localizedName":"Tube Coral Wall Fan","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:vine","localizedName":"Vines","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:void_air","localizedName":"Void Air","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wall_torch","localizedName":"Torch","material":{"powerSource":false,"lightValue":14,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:water","localizedName":"Water","material":{"powerSource":false,"lightValue":0,"hardness":100,"resistance":100,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":true,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":true,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#4040ff","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","material":{"powerSource":false,"lightValue":0,"hardness":0.6,"resistance":0.6,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#e5e533","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wheat","localizedName":"Wheat Crops","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":true,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_banner","localizedName":"White Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_bed","localizedName":"White Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_carpet","localizedName":"White Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_concrete","localizedName":"White Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_tulip","localizedName":"White Tulip","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_wall_banner","localizedName":"White Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:white_wool","localizedName":"White Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","material":{"powerSource":false,"lightValue":0,"hardness":0,"resistance":0,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#007c00","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:wither_skeleton_wall_skull","localizedName":"Wither Skeleton Skull","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","material":{"powerSource":false,"lightValue":0,"hardness":0.2,"resistance":0.2,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","material":{"powerSource":false,"lightValue":0,"hardness":0.1,"resistance":0.1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":true,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","material":{"powerSource":false,"lightValue":0,"hardness":1.8,"resistance":1.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","material":{"powerSource":false,"lightValue":0,"hardness":0.5,"resistance":0.5,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#f7e9a3","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.4,"resistance":1.4,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","material":{"powerSource":false,"lightValue":0,"hardness":2,"resistance":2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#7f3fb2","isTranslucent":true,"hasContainer":true}},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","material":{"powerSource":false,"lightValue":0,"hardness":0.3,"resistance":0.3,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","material":{"powerSource":false,"lightValue":0,"hardness":1.25,"resistance":4.2,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":false,"opaque":true,"replacedDuringPlacement":false,"toolRequired":true,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#707070","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_wall_banner","localizedName":"Yellow Banner","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#8f7748","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","material":{"powerSource":false,"lightValue":0,"hardness":0.8,"resistance":0.8,"ticksRandomly":false,"fullCube":true,"slipperiness":0.6,"liquid":false,"solid":true,"movementBlocker":true,"burnable":true,"opaque":true,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":false,"unpushable":false,"mapColor":"#c7c7c7","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}},{"id":"minecraft:zombie_wall_head","localizedName":"Zombie Head","material":{"powerSource":false,"lightValue":0,"hardness":1,"resistance":1,"ticksRandomly":false,"fullCube":false,"slipperiness":0.6,"liquid":false,"solid":false,"movementBlocker":false,"burnable":false,"opaque":false,"replacedDuringPlacement":false,"toolRequired":false,"fragileWhenPushed":true,"unpushable":false,"mapColor":"#000000","isTranslucent":false,"hasContainer":false}}] diff --git a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.116.json b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.116.json deleted file mode 100644 index b15d6c340..000000000 --- a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.116.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":"minecraft:acacia_button","localizedName":"Acacia Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wall_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:air","localizedName":"Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:allium","localizedName":"Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":30,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite","localizedName":"Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:anvil","localizedName":"Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:attached_melon_stem","localizedName":"Attached Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:attached_pumpkin_stem","localizedName":"Attached Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo","localizedName":"Bamboo","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_sapling","localizedName":"Bamboo Shoot","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrel","localizedName":"Barrel","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrier","localizedName":"Barrier","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:basalt","localizedName":"Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:beacon","localizedName":"Beacon","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bedrock","localizedName":"Bedrock","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beehive","localizedName":"Beehive","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beetroots","localizedName":"Beetroots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bell","localizedName":"Bell","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:birch_button","localizedName":"Birch Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_door","localizedName":"Birch Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_log","localizedName":"Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wall_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_bed","localizedName":"Black Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_wall_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_wool","localizedName":"Black Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blackstone","localizedName":"Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.8,"slipperiness":0.989,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_wall_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bone_block","localizedName":"Bone Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_wall_fan","localizedName":"Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":true,"lightValue":1,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bricks","localizedName":"Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_wall_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_column","localizedName":"Bubble Column","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_wall_fan","localizedName":"Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cactus","localizedName":"Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cake","localizedName":"Cake","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:campfire","localizedName":"Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":true,"lightValue":15,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carrots","localizedName":"Carrots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cauldron","localizedName":"Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cave_air","localizedName":"Cave Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chain","localizedName":"Chain","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chest","localizedName":"Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:clay","localizedName":"Clay","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:coal_block","localizedName":"Block of Coal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobweb","localizedName":"Cobweb","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cocoa","localizedName":"Cocoa","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:command_block","localizedName":"Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:composter","localizedName":"Composter","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:conduit","localizedName":"Conduit","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cornflower","localizedName":"Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_wall_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_wall_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_wall_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:dandelion","localizedName":"Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wall_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_wall_fan","localizedName":"Dead Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_wall_fan","localizedName":"Dead Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_wall_fan","localizedName":"Dead Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_wall_fan","localizedName":"Dead Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_wall_fan","localizedName":"Dead Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite","localizedName":"Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dirt","localizedName":"Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dispenser","localizedName":"Dispenser","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_wall_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dropper","localizedName":"Dropper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_gateway","localizedName":"End Gateway","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal","localizedName":"End Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_rod","localizedName":"End Rod","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_stone","localizedName":"End Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":22.5,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":600,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:farmland","localizedName":"Farmland","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fern","localizedName":"Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire","localizedName":"Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_wall_fan","localizedName":"Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:frosted_ice","localizedName":"Frosted Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:furnace","localizedName":"Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:glass","localizedName":"Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glowstone","localizedName":"Glowstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gold_block","localizedName":"Block of Gold","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite","localizedName":"Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:grass","localizedName":"Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grass_block","localizedName":"Grass Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grass_path","localizedName":"Grass Path","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.65,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.65,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gravel","localizedName":"Gravel","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_wall_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_bed","localizedName":"Green Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_wall_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_wool","localizedName":"Green Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grindstone","localizedName":"Grindstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:hay_block","localizedName":"Hay Bale","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:honey_block","localizedName":"Honey Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:hopper","localizedName":"Hopper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_wall_fan","localizedName":"Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ice","localizedName":"Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_block","localizedName":"Block of Iron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_door","localizedName":"Iron Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o'Lantern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jukebox","localizedName":"Jukebox","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wall_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp","localizedName":"Kelp","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp_plant","localizedName":"Kelp Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ladder","localizedName":"Ladder","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lantern","localizedName":"Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_block","localizedName":"Lapis Lazuli Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:large_fern","localizedName":"Large Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lava","localizedName":"Lava","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100,"hasContainer":false,"lightValue":15,"liquid":true,"mapColor":"#ff0000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lectern","localizedName":"Lectern","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lever","localizedName":"Lever","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_wall_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_wall_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lilac","localizedName":"Lilac","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_wall_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lodestone","localizedName":"Lodestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:loom","localizedName":"Loom","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_wall_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magma_block","localizedName":"Magma Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":3,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:melon","localizedName":"Melon","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:melon_stem","localizedName":"Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:moving_piston","localizedName":"Moving Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mycelium","localizedName":"Mycelium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_portal","localizedName":"Nether Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1,"hasContainer":false,"lightValue":11,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":true}},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:netherrack","localizedName":"Netherrack","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:note_block","localizedName":"Note Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_button","localizedName":"Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_door","localizedName":"Oak Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_log","localizedName":"Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wall_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:observer","localizedName":"Observer","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:obsidian","localizedName":"Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wall_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:peony","localizedName":"Peony","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wall_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:piston","localizedName":"Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:piston_head","localizedName":"Piston Head","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:player_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:player_wall_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:podzol","localizedName":"Podzol","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:poppy","localizedName":"Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potatoes","localizedName":"Potatoes","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_acacia_sapling","localizedName":"Potted Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_allium","localizedName":"Potted Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_azure_bluet","localizedName":"Potted Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_bamboo","localizedName":"Potted Bamboo","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_birch_sapling","localizedName":"Potted Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_blue_orchid","localizedName":"Potted Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_brown_mushroom","localizedName":"Potted Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cactus","localizedName":"Potted Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cornflower","localizedName":"Potted Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_fungus","localizedName":"Potted Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_roots","localizedName":"Potted Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dandelion","localizedName":"Potted Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dark_oak_sapling","localizedName":"Potted Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dead_bush","localizedName":"Potted Dead Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_fern","localizedName":"Potted Fern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_jungle_sapling","localizedName":"Potted Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_lily_of_the_valley","localizedName":"Potted Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oak_sapling","localizedName":"Potted Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_orange_tulip","localizedName":"Potted Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oxeye_daisy","localizedName":"Potted Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_pink_tulip","localizedName":"Potted Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_poppy","localizedName":"Potted Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_mushroom","localizedName":"Potted Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_tulip","localizedName":"Potted Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_spruce_sapling","localizedName":"Potted Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_fungus","localizedName":"Potted Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_roots","localizedName":"Potted Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_white_tulip","localizedName":"Potted White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_wither_rose","localizedName":"Potted Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:prismarine","localizedName":"Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pumpkin_stem","localizedName":"Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_wall_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rail","localizedName":"Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_bed","localizedName":"Red Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sand","localizedName":"Red Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wall_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wool","localizedName":"Red Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wall_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wire","localizedName":"Redstone Wire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sand","localizedName":"Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sandstone","localizedName":"Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":6,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:seagrass","localizedName":"Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_wall_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:slime_block","localizedName":"Slime Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.8,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smoker","localizedName":"Smoker","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:snow","localizedName":"Snow","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:snow_block","localizedName":"Snow Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":true,"lightValue":10,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_fire","localizedName":"Soul Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_wall_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spawner","localizedName":"Spawner","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sponge","localizedName":"Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wall_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:stone","localizedName":"Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_button","localizedName":"Stone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:structure_block","localizedName":"Structure Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:structure_void","localizedName":"Structure Void","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sunflower","localizedName":"Sunflower","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sweet_berry_bush","localizedName":"Sweet Berry Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_seagrass","localizedName":"Tall Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:target","localizedName":"Target","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:terracotta","localizedName":"Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tnt","localizedName":"TNT","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ff0000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire","localizedName":"Tripwire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_wall_fan","localizedName":"Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines_plant","localizedName":"Twisting Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:vine","localizedName":"Vines","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.2,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:void_air","localizedName":"Void Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wall_torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_button","localizedName":"Warped Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_door","localizedName":"Warped Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wall_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:water","localizedName":"Water","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:weeping_vines_plant","localizedName":"Weeping Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wheat","localizedName":"Wheat Crops","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_bed","localizedName":"White Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_carpet","localizedName":"White Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_concrete","localizedName":"White Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_tulip","localizedName":"White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wall_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wool","localizedName":"White Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_wall_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_wall_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_wall_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}}] \ No newline at end of file diff --git a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.117.json b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.117.json deleted file mode 100644 index 4f60b0771..000000000 --- a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.117.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":"minecraft:acacia_button","localizedName":"Acacia Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wall_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:air","localizedName":"Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:allium","localizedName":"Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:amethyst_block","localizedName":"Block of Amethyst","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:amethyst_cluster","localizedName":"Amethyst Cluster","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":5,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":30.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite","localizedName":"Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:anvil","localizedName":"Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:attached_melon_stem","localizedName":"Attached Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:attached_pumpkin_stem","localizedName":"Attached Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azalea","localizedName":"Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azalea_leaves","localizedName":"Azalea Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo","localizedName":"Bamboo","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_sapling","localizedName":"Bamboo Shoot","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrel","localizedName":"Barrel","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrier","localizedName":"Barrier","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:basalt","localizedName":"Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:beacon","localizedName":"Beacon","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bedrock","localizedName":"Bedrock","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beehive","localizedName":"Beehive","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beetroots","localizedName":"Beetroots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bell","localizedName":"Bell","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:big_dripleaf","localizedName":"Big Dripleaf","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:big_dripleaf_stem","localizedName":"Big Dripleaf Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_button","localizedName":"Birch Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_door","localizedName":"Birch Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_log","localizedName":"Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wall_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_bed","localizedName":"Black Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_candle","localizedName":"Black Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_candle_cake","localizedName":"Cake with Black Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_wall_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_wool","localizedName":"Black Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blackstone","localizedName":"Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_candle","localizedName":"Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_candle_cake","localizedName":"Cake with Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.8,"slipperiness":0.989,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_wall_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bone_block","localizedName":"Bone Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_wall_fan","localizedName":"Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":true,"lightValue":1,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bricks","localizedName":"Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_candle","localizedName":"Brown Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_candle_cake","localizedName":"Cake with Brown Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_wall_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_column","localizedName":"Bubble Column","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_wall_fan","localizedName":"Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:budding_amethyst","localizedName":"Budding Amethyst","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cactus","localizedName":"Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cake","localizedName":"Cake","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:calcite","localizedName":"Calcite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:campfire","localizedName":"Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":true,"lightValue":15,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:candle","localizedName":"Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:candle_cake","localizedName":"Cake with Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carrots","localizedName":"Carrots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cauldron","localizedName":"Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cave_air","localizedName":"Cave Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cave_vines","localizedName":"Cave Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cave_vines_plant","localizedName":"Cave Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chain","localizedName":"Chain","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chest","localizedName":"Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:chiseled_deepslate","localizedName":"Chiseled Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:clay","localizedName":"Clay","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:coal_block","localizedName":"Block of Coal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cobbled_deepslate","localizedName":"Cobbled Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_slab","localizedName":"Cobbled Deepslate Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_stairs","localizedName":"Cobbled Deepslate Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_wall","localizedName":"Cobbled Deepslate Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobweb","localizedName":"Cobweb","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":4.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cocoa","localizedName":"Cocoa","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:command_block","localizedName":"Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:composter","localizedName":"Composter","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:conduit","localizedName":"Conduit","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:copper_block","localizedName":"Block of Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:copper_ore","localizedName":"Copper Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cornflower","localizedName":"Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cracked_deepslate_bricks","localizedName":"Cracked Deepslate Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_deepslate_tiles","localizedName":"Cracked Deepslate Tiles","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_wall_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_wall_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper","localizedName":"Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper_slab","localizedName":"Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper_stairs","localizedName":"Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_candle","localizedName":"Cyan Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_candle_cake","localizedName":"Cake with Cyan Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_wall_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:dandelion","localizedName":"Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wall_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_wall_fan","localizedName":"Dead Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_wall_fan","localizedName":"Dead Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_wall_fan","localizedName":"Dead Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_wall_fan","localizedName":"Dead Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_wall_fan","localizedName":"Dead Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate","localizedName":"Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_slab","localizedName":"Deepslate Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_stairs","localizedName":"Deepslate Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_wall","localizedName":"Deepslate Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_bricks","localizedName":"Deepslate Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_coal_ore","localizedName":"Deepslate Coal Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_copper_ore","localizedName":"Deepslate Copper Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_diamond_ore","localizedName":"Deepslate Diamond Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_emerald_ore","localizedName":"Deepslate Emerald Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_gold_ore","localizedName":"Deepslate Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_iron_ore","localizedName":"Deepslate Iron Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_lapis_ore","localizedName":"Deepslate Lapis Lazuli Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_redstone_ore","localizedName":"Deepslate Redstone Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_slab","localizedName":"Deepslate Tile Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_stairs","localizedName":"Deepslate Tile Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_wall","localizedName":"Deepslate Tile Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tiles","localizedName":"Deepslate Tiles","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite","localizedName":"Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dirt","localizedName":"Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dirt_path","localizedName":"Dirt Path","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.65,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.65,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dispenser","localizedName":"Dispenser","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_wall_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dripstone_block","localizedName":"Dripstone Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dropper","localizedName":"Dropper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_gateway","localizedName":"End Gateway","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal","localizedName":"End Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_rod","localizedName":"End Rod","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_stone","localizedName":"End Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":22.5,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":600.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_copper","localizedName":"Exposed Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper","localizedName":"Exposed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper_slab","localizedName":"Exposed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper_stairs","localizedName":"Exposed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:farmland","localizedName":"Farmland","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fern","localizedName":"Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire","localizedName":"Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_wall_fan","localizedName":"Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flowering_azalea","localizedName":"Flowering Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flowering_azalea_leaves","localizedName":"Flowering Azalea Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:frosted_ice","localizedName":"Frosted Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:furnace","localizedName":"Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:glass","localizedName":"Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glow_lichen","localizedName":"Glow Lichen","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.2,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glowstone","localizedName":"Glowstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gold_block","localizedName":"Block of Gold","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite","localizedName":"Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:grass","localizedName":"Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grass_block","localizedName":"Grass Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gravel","localizedName":"Gravel","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_candle","localizedName":"Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_candle_cake","localizedName":"Cake with Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_wall_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_bed","localizedName":"Green Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_candle","localizedName":"Green Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_candle_cake","localizedName":"Cake with Green Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_wall_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_wool","localizedName":"Green Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grindstone","localizedName":"Grindstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:hanging_roots","localizedName":"Hanging Roots","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:hay_block","localizedName":"Hay Bale","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:honey_block","localizedName":"Honey Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:hopper","localizedName":"Hopper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_wall_fan","localizedName":"Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ice","localizedName":"Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_deepslate","localizedName":"Infested Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_block","localizedName":"Block of Iron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_door","localizedName":"Iron Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o\u0027Lantern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jukebox","localizedName":"Jukebox","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wall_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp","localizedName":"Kelp","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp_plant","localizedName":"Kelp Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ladder","localizedName":"Ladder","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lantern","localizedName":"Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_block","localizedName":"Block of Lapis Lazuli","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:large_amethyst_bud","localizedName":"Large Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":4,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:large_fern","localizedName":"Large Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lava","localizedName":"Lava","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100.0,"hasContainer":false,"lightValue":15,"liquid":true,"mapColor":"#ff0000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lava_cauldron","localizedName":"Lava Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lectern","localizedName":"Lectern","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lever","localizedName":"Lever","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light","localizedName":"Light","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":3600000.8,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_candle","localizedName":"Light Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_candle_cake","localizedName":"Cake with Light Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_wall_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_candle","localizedName":"Light Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_candle_cake","localizedName":"Cake with Light Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_wall_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lightning_rod","localizedName":"Lightning Rod","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lilac","localizedName":"Lilac","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_candle","localizedName":"Lime Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_candle_cake","localizedName":"Cake with Lime Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_wall_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lodestone","localizedName":"Lodestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:loom","localizedName":"Loom","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_candle","localizedName":"Magenta Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_candle_cake","localizedName":"Cake with Magenta Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_wall_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magma_block","localizedName":"Magma Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":3,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:medium_amethyst_bud","localizedName":"Medium Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":2,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:melon","localizedName":"Melon","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:melon_stem","localizedName":"Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:moss_block","localizedName":"Moss Block","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:moss_carpet","localizedName":"Moss Carpet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:moving_piston","localizedName":"Moving Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mycelium","localizedName":"Mycelium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_portal","localizedName":"Nether Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":11,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":true}},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:netherrack","localizedName":"Netherrack","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:note_block","localizedName":"Note Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_button","localizedName":"Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_door","localizedName":"Oak Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_log","localizedName":"Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wall_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:observer","localizedName":"Observer","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:obsidian","localizedName":"Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_candle","localizedName":"Orange Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_candle_cake","localizedName":"Cake with Orange Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wall_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oxidized_copper","localizedName":"Oxidized Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper","localizedName":"Oxidized Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper_slab","localizedName":"Oxidized Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper_stairs","localizedName":"Oxidized Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:peony","localizedName":"Peony","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_candle","localizedName":"Pink Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_candle_cake","localizedName":"Cake with Pink Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wall_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:piston","localizedName":"Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:piston_head","localizedName":"Piston Head","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:player_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:player_wall_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:podzol","localizedName":"Podzol","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pointed_dripstone","localizedName":"Pointed Dripstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate","localizedName":"Polished Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_slab","localizedName":"Polished Deepslate Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_stairs","localizedName":"Polished Deepslate Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_wall","localizedName":"Polished Deepslate Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:poppy","localizedName":"Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potatoes","localizedName":"Potatoes","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_acacia_sapling","localizedName":"Potted Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_allium","localizedName":"Potted Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_azalea_bush","localizedName":"Potted Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_azure_bluet","localizedName":"Potted Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_bamboo","localizedName":"Potted Bamboo","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_birch_sapling","localizedName":"Potted Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_blue_orchid","localizedName":"Potted Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_brown_mushroom","localizedName":"Potted Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cactus","localizedName":"Potted Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cornflower","localizedName":"Potted Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_fungus","localizedName":"Potted Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_roots","localizedName":"Potted Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dandelion","localizedName":"Potted Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dark_oak_sapling","localizedName":"Potted Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dead_bush","localizedName":"Potted Dead Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_fern","localizedName":"Potted Fern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_flowering_azalea_bush","localizedName":"Potted Flowering Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_jungle_sapling","localizedName":"Potted Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_lily_of_the_valley","localizedName":"Potted Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oak_sapling","localizedName":"Potted Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_orange_tulip","localizedName":"Potted Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oxeye_daisy","localizedName":"Potted Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_pink_tulip","localizedName":"Potted Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_poppy","localizedName":"Potted Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_mushroom","localizedName":"Potted Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_tulip","localizedName":"Potted Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_spruce_sapling","localizedName":"Potted Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_fungus","localizedName":"Potted Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_roots","localizedName":"Potted Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_white_tulip","localizedName":"Potted White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_wither_rose","localizedName":"Potted Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:powder_snow","localizedName":"Powder Snow","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.25,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:powder_snow_cauldron","localizedName":"Powder Snow Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:prismarine","localizedName":"Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pumpkin_stem","localizedName":"Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_candle","localizedName":"Purple Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_candle_cake","localizedName":"Cake with Purple Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_wall_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rail","localizedName":"Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:raw_copper_block","localizedName":"Block of Raw Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:raw_gold_block","localizedName":"Block of Raw Gold","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:raw_iron_block","localizedName":"Block of Raw Iron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_bed","localizedName":"Red Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_candle","localizedName":"Red Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_candle_cake","localizedName":"Cake with Red Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sand","localizedName":"Red Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wall_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wool","localizedName":"Red Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wall_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wire","localizedName":"Redstone Wire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rooted_dirt","localizedName":"Rooted Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sand","localizedName":"Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sandstone","localizedName":"Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_sensor","localizedName":"Sculk Sensor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":6,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:seagrass","localizedName":"Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_wall_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:slime_block","localizedName":"Slime Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.8,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:small_amethyst_bud","localizedName":"Small Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:small_dripleaf","localizedName":"Small Dripleaf","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smoker","localizedName":"Smoker","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_basalt","localizedName":"Smooth Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:snow","localizedName":"Snow","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:snow_block","localizedName":"Snow Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":true,"lightValue":10,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_fire","localizedName":"Soul Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_wall_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spawner","localizedName":"Spawner","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sponge","localizedName":"Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spore_blossom","localizedName":"Spore Blossom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wall_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:stone","localizedName":"Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_button","localizedName":"Stone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:structure_block","localizedName":"Structure Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:structure_void","localizedName":"Structure Void","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sunflower","localizedName":"Sunflower","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sweet_berry_bush","localizedName":"Sweet Berry Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_seagrass","localizedName":"Tall Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:target","localizedName":"Target","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:terracotta","localizedName":"Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tinted_glass","localizedName":"Tinted Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tnt","localizedName":"TNT","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ff0000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire","localizedName":"Tripwire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_wall_fan","localizedName":"Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tuff","localizedName":"Tuff","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines_plant","localizedName":"Twisting Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:vine","localizedName":"Vines","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.2,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:void_air","localizedName":"Void Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wall_torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_button","localizedName":"Warped Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_door","localizedName":"Warped Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wall_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:water","localizedName":"Water","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100.0,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:water_cauldron","localizedName":"Water Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_copper_block","localizedName":"Waxed Block of Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper","localizedName":"Waxed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper_slab","localizedName":"Waxed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper_stairs","localizedName":"Waxed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_copper","localizedName":"Waxed Exposed Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper","localizedName":"Waxed Exposed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper_slab","localizedName":"Waxed Exposed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper_stairs","localizedName":"Waxed Exposed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_copper","localizedName":"Waxed Oxidized Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper","localizedName":"Waxed Oxidized Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper_slab","localizedName":"Waxed Oxidized Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper_stairs","localizedName":"Waxed Oxidized Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_copper","localizedName":"Waxed Weathered Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper","localizedName":"Waxed Weathered Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper_slab","localizedName":"Waxed Weathered Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper_stairs","localizedName":"Waxed Weathered Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_copper","localizedName":"Weathered Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper","localizedName":"Weathered Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper_slab","localizedName":"Weathered Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper_stairs","localizedName":"Weathered Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:weeping_vines_plant","localizedName":"Weeping Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wheat","localizedName":"Wheat Crops","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_bed","localizedName":"White Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_candle","localizedName":"White Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_candle_cake","localizedName":"Cake with White Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_carpet","localizedName":"White Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_concrete","localizedName":"White Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_tulip","localizedName":"White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wall_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wool","localizedName":"White Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_wall_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_candle","localizedName":"Yellow Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_candle_cake","localizedName":"Cake with Yellow Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_wall_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_wall_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}}] diff --git a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.119.json b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.119.json deleted file mode 100644 index 688a8c97d..000000000 --- a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.119.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":"minecraft:acacia_button","localizedName":"Acacia Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wall_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:air","localizedName":"Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:allium","localizedName":"Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:amethyst_block","localizedName":"Block of Amethyst","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:amethyst_cluster","localizedName":"Amethyst Cluster","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":5,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":30.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite","localizedName":"Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:anvil","localizedName":"Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:attached_melon_stem","localizedName":"Attached Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:attached_pumpkin_stem","localizedName":"Attached Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azalea","localizedName":"Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azalea_leaves","localizedName":"Azalea Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo","localizedName":"Bamboo","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_sapling","localizedName":"Bamboo Shoot","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrel","localizedName":"Barrel","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrier","localizedName":"Barrier","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:basalt","localizedName":"Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:beacon","localizedName":"Beacon","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bedrock","localizedName":"Bedrock","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beehive","localizedName":"Beehive","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beetroots","localizedName":"Beetroots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bell","localizedName":"Bell","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:big_dripleaf","localizedName":"Big Dripleaf","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:big_dripleaf_stem","localizedName":"Big Dripleaf Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_button","localizedName":"Birch Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_door","localizedName":"Birch Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_log","localizedName":"Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wall_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_bed","localizedName":"Black Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_candle","localizedName":"Black Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_candle_cake","localizedName":"Cake with Black Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_wall_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_wool","localizedName":"Black Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blackstone","localizedName":"Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_candle","localizedName":"Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_candle_cake","localizedName":"Cake with Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.8,"slipperiness":0.989,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_wall_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bone_block","localizedName":"Bone Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_wall_fan","localizedName":"Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":true,"lightValue":1,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bricks","localizedName":"Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_candle","localizedName":"Brown Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_candle_cake","localizedName":"Cake with Brown Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_wall_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_column","localizedName":"Bubble Column","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_wall_fan","localizedName":"Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:budding_amethyst","localizedName":"Budding Amethyst","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cactus","localizedName":"Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cake","localizedName":"Cake","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:calcite","localizedName":"Calcite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:campfire","localizedName":"Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":true,"lightValue":15,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:candle","localizedName":"Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:candle_cake","localizedName":"Cake with Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carrots","localizedName":"Carrots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cauldron","localizedName":"Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cave_air","localizedName":"Cave Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cave_vines","localizedName":"Cave Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cave_vines_plant","localizedName":"Cave Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chain","localizedName":"Chain","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chest","localizedName":"Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:chiseled_deepslate","localizedName":"Chiseled Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:clay","localizedName":"Clay","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:coal_block","localizedName":"Block of Coal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cobbled_deepslate","localizedName":"Cobbled Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_slab","localizedName":"Cobbled Deepslate Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_stairs","localizedName":"Cobbled Deepslate Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_wall","localizedName":"Cobbled Deepslate Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobweb","localizedName":"Cobweb","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":4.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cocoa","localizedName":"Cocoa","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:command_block","localizedName":"Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:composter","localizedName":"Composter","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:conduit","localizedName":"Conduit","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:copper_block","localizedName":"Block of Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:copper_ore","localizedName":"Copper Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cornflower","localizedName":"Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cracked_deepslate_bricks","localizedName":"Cracked Deepslate Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_deepslate_tiles","localizedName":"Cracked Deepslate Tiles","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_wall_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_wall_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper","localizedName":"Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper_slab","localizedName":"Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper_stairs","localizedName":"Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_candle","localizedName":"Cyan Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_candle_cake","localizedName":"Cake with Cyan Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_wall_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:dandelion","localizedName":"Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wall_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_wall_fan","localizedName":"Dead Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_wall_fan","localizedName":"Dead Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_wall_fan","localizedName":"Dead Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_wall_fan","localizedName":"Dead Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_wall_fan","localizedName":"Dead Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate","localizedName":"Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_slab","localizedName":"Deepslate Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_stairs","localizedName":"Deepslate Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_wall","localizedName":"Deepslate Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_bricks","localizedName":"Deepslate Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_coal_ore","localizedName":"Deepslate Coal Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_copper_ore","localizedName":"Deepslate Copper Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_diamond_ore","localizedName":"Deepslate Diamond Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_emerald_ore","localizedName":"Deepslate Emerald Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_gold_ore","localizedName":"Deepslate Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_iron_ore","localizedName":"Deepslate Iron Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_lapis_ore","localizedName":"Deepslate Lapis Lazuli Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_redstone_ore","localizedName":"Deepslate Redstone Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_slab","localizedName":"Deepslate Tile Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_stairs","localizedName":"Deepslate Tile Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_wall","localizedName":"Deepslate Tile Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tiles","localizedName":"Deepslate Tiles","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite","localizedName":"Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dirt","localizedName":"Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dirt_path","localizedName":"Dirt Path","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.65,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.65,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dispenser","localizedName":"Dispenser","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_wall_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dripstone_block","localizedName":"Dripstone Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dropper","localizedName":"Dropper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_gateway","localizedName":"End Gateway","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal","localizedName":"End Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_rod","localizedName":"End Rod","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_stone","localizedName":"End Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":22.5,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":600.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_copper","localizedName":"Exposed Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper","localizedName":"Exposed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper_slab","localizedName":"Exposed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper_stairs","localizedName":"Exposed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:farmland","localizedName":"Farmland","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fern","localizedName":"Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire","localizedName":"Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_wall_fan","localizedName":"Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flowering_azalea","localizedName":"Flowering Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flowering_azalea_leaves","localizedName":"Flowering Azalea Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:frogspawn","localizedName":"Frogspawn","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:frosted_ice","localizedName":"Frosted Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:furnace","localizedName":"Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:glass","localizedName":"Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glow_lichen","localizedName":"Glow Lichen","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.2,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glowstone","localizedName":"Glowstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gold_block","localizedName":"Block of Gold","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite","localizedName":"Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:grass","localizedName":"Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grass_block","localizedName":"Grass Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gravel","localizedName":"Gravel","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_candle","localizedName":"Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_candle_cake","localizedName":"Cake with Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_wall_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_bed","localizedName":"Green Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_candle","localizedName":"Green Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_candle_cake","localizedName":"Cake with Green Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_wall_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_wool","localizedName":"Green Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grindstone","localizedName":"Grindstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:hanging_roots","localizedName":"Hanging Roots","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:hay_block","localizedName":"Hay Bale","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:honey_block","localizedName":"Honey Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:hopper","localizedName":"Hopper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_wall_fan","localizedName":"Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ice","localizedName":"Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_deepslate","localizedName":"Infested Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_block","localizedName":"Block of Iron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_door","localizedName":"Iron Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o\u0027Lantern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jukebox","localizedName":"Jukebox","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wall_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp","localizedName":"Kelp","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp_plant","localizedName":"Kelp Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ladder","localizedName":"Ladder","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lantern","localizedName":"Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_block","localizedName":"Block of Lapis Lazuli","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:large_amethyst_bud","localizedName":"Large Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":4,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:large_fern","localizedName":"Large Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lava","localizedName":"Lava","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100.0,"hasContainer":false,"lightValue":15,"liquid":true,"mapColor":"#ff0000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lava_cauldron","localizedName":"Lava Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lectern","localizedName":"Lectern","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lever","localizedName":"Lever","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light","localizedName":"Light","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":3600000.8,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_candle","localizedName":"Light Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_candle_cake","localizedName":"Cake with Light Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_wall_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_candle","localizedName":"Light Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_candle_cake","localizedName":"Cake with Light Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_wall_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lightning_rod","localizedName":"Lightning Rod","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lilac","localizedName":"Lilac","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_candle","localizedName":"Lime Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_candle_cake","localizedName":"Cake with Lime Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_wall_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lodestone","localizedName":"Lodestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:loom","localizedName":"Loom","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_candle","localizedName":"Magenta Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_candle_cake","localizedName":"Cake with Magenta Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_wall_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magma_block","localizedName":"Magma Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":3,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mangrove_button","localizedName":"Mangrove Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_door","localizedName":"Mangrove Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_fence","localizedName":"Mangrove Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_fence_gate","localizedName":"Mangrove Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_leaves","localizedName":"Mangrove Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_log","localizedName":"Mangrove Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_planks","localizedName":"Mangrove Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_pressure_plate","localizedName":"Mangrove Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_propagule","localizedName":"Mangrove Propagule","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_roots","localizedName":"Mangrove Roots","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_sign","localizedName":"Mangrove Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_slab","localizedName":"Mangrove Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_stairs","localizedName":"Mangrove Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_trapdoor","localizedName":"Mangrove Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_wall_sign","localizedName":"Mangrove Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_wood","localizedName":"Mangrove Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:medium_amethyst_bud","localizedName":"Medium Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":2,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:melon","localizedName":"Melon","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:melon_stem","localizedName":"Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:moss_block","localizedName":"Moss Block","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:moss_carpet","localizedName":"Moss Carpet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:moving_piston","localizedName":"Moving Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:mud","localizedName":"Mud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mud_brick_slab","localizedName":"Mud Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mud_brick_stairs","localizedName":"Mud Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mud_brick_wall","localizedName":"Mud Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mud_bricks","localizedName":"Mud Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:muddy_mangrove_roots","localizedName":"Muddy Mangrove Roots","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mycelium","localizedName":"Mycelium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_portal","localizedName":"Nether Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":11,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":true}},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:netherrack","localizedName":"Netherrack","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:note_block","localizedName":"Note Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_button","localizedName":"Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_door","localizedName":"Oak Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_log","localizedName":"Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wall_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:observer","localizedName":"Observer","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:obsidian","localizedName":"Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:ochre_froglight","localizedName":"Ochre Froglight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_candle","localizedName":"Orange Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_candle_cake","localizedName":"Cake with Orange Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wall_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oxidized_copper","localizedName":"Oxidized Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper","localizedName":"Oxidized Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper_slab","localizedName":"Oxidized Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper_stairs","localizedName":"Oxidized Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:packed_mud","localizedName":"Packed Mud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pearlescent_froglight","localizedName":"Pearlescent Froglight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:peony","localizedName":"Peony","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_candle","localizedName":"Pink Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_candle_cake","localizedName":"Cake with Pink Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wall_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:piston","localizedName":"Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:piston_head","localizedName":"Piston Head","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:player_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:player_wall_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:podzol","localizedName":"Podzol","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pointed_dripstone","localizedName":"Pointed Dripstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate","localizedName":"Polished Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_slab","localizedName":"Polished Deepslate Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_stairs","localizedName":"Polished Deepslate Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_wall","localizedName":"Polished Deepslate Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:poppy","localizedName":"Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potatoes","localizedName":"Potatoes","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_acacia_sapling","localizedName":"Potted Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_allium","localizedName":"Potted Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_azalea_bush","localizedName":"Potted Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_azure_bluet","localizedName":"Potted Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_bamboo","localizedName":"Potted Bamboo","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_birch_sapling","localizedName":"Potted Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_blue_orchid","localizedName":"Potted Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_brown_mushroom","localizedName":"Potted Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cactus","localizedName":"Potted Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cornflower","localizedName":"Potted Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_fungus","localizedName":"Potted Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_roots","localizedName":"Potted Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dandelion","localizedName":"Potted Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dark_oak_sapling","localizedName":"Potted Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dead_bush","localizedName":"Potted Dead Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_fern","localizedName":"Potted Fern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_flowering_azalea_bush","localizedName":"Potted Flowering Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_jungle_sapling","localizedName":"Potted Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_lily_of_the_valley","localizedName":"Potted Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_mangrove_propagule","localizedName":"Potted Mangrove Propagule","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oak_sapling","localizedName":"Potted Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_orange_tulip","localizedName":"Potted Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oxeye_daisy","localizedName":"Potted Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_pink_tulip","localizedName":"Potted Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_poppy","localizedName":"Potted Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_mushroom","localizedName":"Potted Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_tulip","localizedName":"Potted Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_spruce_sapling","localizedName":"Potted Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_fungus","localizedName":"Potted Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_roots","localizedName":"Potted Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_white_tulip","localizedName":"Potted White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_wither_rose","localizedName":"Potted Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:powder_snow","localizedName":"Powder Snow","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.25,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:powder_snow_cauldron","localizedName":"Powder Snow Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:prismarine","localizedName":"Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pumpkin_stem","localizedName":"Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_candle","localizedName":"Purple Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_candle_cake","localizedName":"Cake with Purple Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_wall_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rail","localizedName":"Rail","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:raw_copper_block","localizedName":"Block of Raw Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:raw_gold_block","localizedName":"Block of Raw Gold","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:raw_iron_block","localizedName":"Block of Raw Iron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_bed","localizedName":"Red Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_candle","localizedName":"Red Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_candle_cake","localizedName":"Cake with Red Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sand","localizedName":"Red Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wall_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wool","localizedName":"Red Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wall_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wire","localizedName":"Redstone Wire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:reinforced_deepslate","localizedName":"Reinforced Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":55.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rooted_dirt","localizedName":"Rooted Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sand","localizedName":"Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sandstone","localizedName":"Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk","localizedName":"Sculk","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_catalyst","localizedName":"Sculk Catalyst","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":6,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_sensor","localizedName":"Sculk Sensor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_shrieker","localizedName":"Sculk Shrieker","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_vein","localizedName":"Sculk Vein","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":6,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:seagrass","localizedName":"Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_wall_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:slime_block","localizedName":"Slime Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.8,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:small_amethyst_bud","localizedName":"Small Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:small_dripleaf","localizedName":"Small Dripleaf","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smoker","localizedName":"Smoker","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_basalt","localizedName":"Smooth Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:snow","localizedName":"Snow","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:snow_block","localizedName":"Snow Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":true,"lightValue":10,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_fire","localizedName":"Soul Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_wall_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spawner","localizedName":"Spawner","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sponge","localizedName":"Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spore_blossom","localizedName":"Spore Blossom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wall_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:stone","localizedName":"Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_button","localizedName":"Stone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_mangrove_log","localizedName":"Stripped Mangrove Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_mangrove_wood","localizedName":"Stripped Mangrove Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:structure_block","localizedName":"Structure Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:structure_void","localizedName":"Structure Void","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sunflower","localizedName":"Sunflower","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sweet_berry_bush","localizedName":"Sweet Berry Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_seagrass","localizedName":"Tall Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:target","localizedName":"Target","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:terracotta","localizedName":"Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tinted_glass","localizedName":"Tinted Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tnt","localizedName":"TNT","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ff0000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire","localizedName":"Tripwire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_wall_fan","localizedName":"Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tuff","localizedName":"Tuff","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines_plant","localizedName":"Twisting Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:verdant_froglight","localizedName":"Verdant Froglight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:vine","localizedName":"Vines","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.2,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:void_air","localizedName":"Void Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wall_torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_button","localizedName":"Warped Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_door","localizedName":"Warped Door","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wall_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:water","localizedName":"Water","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100.0,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:water_cauldron","localizedName":"Water Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_copper_block","localizedName":"Waxed Block of Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper","localizedName":"Waxed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper_slab","localizedName":"Waxed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper_stairs","localizedName":"Waxed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_copper","localizedName":"Waxed Exposed Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper","localizedName":"Waxed Exposed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper_slab","localizedName":"Waxed Exposed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper_stairs","localizedName":"Waxed Exposed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_copper","localizedName":"Waxed Oxidized Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper","localizedName":"Waxed Oxidized Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper_slab","localizedName":"Waxed Oxidized Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper_stairs","localizedName":"Waxed Oxidized Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_copper","localizedName":"Waxed Weathered Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper","localizedName":"Waxed Weathered Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper_slab","localizedName":"Waxed Weathered Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper_stairs","localizedName":"Waxed Weathered Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_copper","localizedName":"Weathered Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper","localizedName":"Weathered Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper_slab","localizedName":"Weathered Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper_stairs","localizedName":"Weathered Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:weeping_vines_plant","localizedName":"Weeping Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wheat","localizedName":"Wheat Crops","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_bed","localizedName":"White Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_candle","localizedName":"White Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_candle_cake","localizedName":"Cake with White Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_carpet","localizedName":"White Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_concrete","localizedName":"White Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_tulip","localizedName":"White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wall_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wool","localizedName":"White Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_wall_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_candle","localizedName":"Yellow Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_candle_cake","localizedName":"Cake with Yellow Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_wall_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_wall_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}}] diff --git a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.121.json b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.121.json new file mode 100644 index 000000000..c86ab5e46 --- /dev/null +++ b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.121.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_button","localizedName":"Acacia Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_hanging_sign","localizedName":"Acacia Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wall_hanging_sign","localizedName":"Acacia Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wall_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:air","localizedName":"Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:allium","localizedName":"Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:amethyst_block","localizedName":"Block of Amethyst","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:amethyst_cluster","localizedName":"Amethyst Cluster","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":5,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":30.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite","localizedName":"Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:anvil","localizedName":"Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:attached_melon_stem","localizedName":"Attached Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:attached_pumpkin_stem","localizedName":"Attached Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azalea","localizedName":"Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azalea_leaves","localizedName":"Azalea Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo","localizedName":"Bamboo","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_block","localizedName":"Block of Bamboo","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_button","localizedName":"Bamboo Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_door","localizedName":"Bamboo Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_fence","localizedName":"Bamboo Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_fence_gate","localizedName":"Bamboo Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_hanging_sign","localizedName":"Bamboo Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_mosaic","localizedName":"Bamboo Mosaic","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_mosaic_slab","localizedName":"Bamboo Mosaic Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_mosaic_stairs","localizedName":"Bamboo Mosaic Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_planks","localizedName":"Bamboo Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_pressure_plate","localizedName":"Bamboo Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_sapling","localizedName":"Bamboo Shoot","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_sign","localizedName":"Bamboo Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_slab","localizedName":"Bamboo Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_stairs","localizedName":"Bamboo Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_trapdoor","localizedName":"Bamboo Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_wall_hanging_sign","localizedName":"Bamboo Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_wall_sign","localizedName":"Bamboo Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrel","localizedName":"Barrel","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrier","localizedName":"Barrier","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:basalt","localizedName":"Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:beacon","localizedName":"Beacon","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bedrock","localizedName":"Bedrock","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beehive","localizedName":"Beehive","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beetroots","localizedName":"Beetroots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bell","localizedName":"Bell","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#faee4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:big_dripleaf","localizedName":"Big Dripleaf","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:big_dripleaf_stem","localizedName":"Big Dripleaf Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_button","localizedName":"Birch Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_door","localizedName":"Birch Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_hanging_sign","localizedName":"Birch Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_log","localizedName":"Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wall_hanging_sign","localizedName":"Birch Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wall_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_bed","localizedName":"Black Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_candle","localizedName":"Black Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_candle_cake","localizedName":"Cake with Black Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#251610","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_wall_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_wool","localizedName":"Black Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blackstone","localizedName":"Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_candle","localizedName":"Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_candle_cake","localizedName":"Cake with Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.8,"slipperiness":0.989,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c3e5c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_wall_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bone_block","localizedName":"Bone Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_wall_fan","localizedName":"Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":true,"lightValue":1,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bricks","localizedName":"Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_candle","localizedName":"Brown Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_candle_cake","localizedName":"Cake with Brown Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#664c33","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c3223","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_wall_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_column","localizedName":"Bubble Column","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_wall_fan","localizedName":"Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:budding_amethyst","localizedName":"Budding Amethyst","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cactus","localizedName":"Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cake","localizedName":"Cake","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:calcite","localizedName":"Calcite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:calibrated_sculk_sensor","localizedName":"Calibrated Sculk Sensor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:campfire","localizedName":"Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":true,"lightValue":15,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:candle","localizedName":"Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:candle_cake","localizedName":"Cake with Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carrots","localizedName":"Carrots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cauldron","localizedName":"Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cave_air","localizedName":"Cave Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cave_vines","localizedName":"Cave Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cave_vines_plant","localizedName":"Cave Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chain","localizedName":"Chain","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cherry_button","localizedName":"Cherry Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_door","localizedName":"Cherry Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_fence","localizedName":"Cherry Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_fence_gate","localizedName":"Cherry Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_hanging_sign","localizedName":"Cherry Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a04d4e","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_leaves","localizedName":"Cherry Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_log","localizedName":"Cherry Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_planks","localizedName":"Cherry Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_pressure_plate","localizedName":"Cherry Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_sapling","localizedName":"Cherry Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_sign","localizedName":"Cherry Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_slab","localizedName":"Cherry Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_stairs","localizedName":"Cherry Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_trapdoor","localizedName":"Cherry Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_wall_hanging_sign","localizedName":"Cherry Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a04d4e","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_wall_sign","localizedName":"Cherry Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_wood","localizedName":"Cherry Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chest","localizedName":"Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:chiseled_bookshelf","localizedName":"Chiseled Bookshelf","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chiseled_copper","localizedName":"Chiseled Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_deepslate","localizedName":"Chiseled Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_tuff","localizedName":"Chiseled Tuff","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_tuff_bricks","localizedName":"Chiseled Tuff Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:clay","localizedName":"Clay","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:coal_block","localizedName":"Block of Coal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cobbled_deepslate","localizedName":"Cobbled Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_slab","localizedName":"Cobbled Deepslate Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_stairs","localizedName":"Cobbled Deepslate Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_wall","localizedName":"Cobbled Deepslate Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobweb","localizedName":"Cobweb","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":4.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cocoa","localizedName":"Cocoa","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:command_block","localizedName":"Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:composter","localizedName":"Composter","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:conduit","localizedName":"Conduit","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:copper_block","localizedName":"Block of Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:copper_bulb","localizedName":"Copper Bulb","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:copper_door","localizedName":"Copper Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:copper_grate","localizedName":"Copper Grate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:copper_ore","localizedName":"Copper Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:copper_trapdoor","localizedName":"Copper Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cornflower","localizedName":"Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cracked_deepslate_bricks","localizedName":"Cracked Deepslate Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_deepslate_tiles","localizedName":"Cracked Deepslate Tiles","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crafter","localizedName":"Crafter","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_wall_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_hanging_sign","localizedName":"Crimson Hanging Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5c191d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#bd3031","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_wall_hanging_sign","localizedName":"Crimson Hanging Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_wall_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper","localizedName":"Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper_slab","localizedName":"Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper_stairs","localizedName":"Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_candle","localizedName":"Cyan Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_candle_cake","localizedName":"Cake with Cyan Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#575c5c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_wall_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:dandelion","localizedName":"Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_hanging_sign","localizedName":"Dark Oak Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wall_hanging_sign","localizedName":"Dark Oak Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wall_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_wall_fan","localizedName":"Dead Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_wall_fan","localizedName":"Dead Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_wall_fan","localizedName":"Dead Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_wall_fan","localizedName":"Dead Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_wall_fan","localizedName":"Dead Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:decorated_pot","localizedName":"Decorated Pot","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8e3c2e","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:deepslate","localizedName":"Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_slab","localizedName":"Deepslate Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_stairs","localizedName":"Deepslate Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_wall","localizedName":"Deepslate Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_bricks","localizedName":"Deepslate Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_coal_ore","localizedName":"Deepslate Coal Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_copper_ore","localizedName":"Deepslate Copper Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_diamond_ore","localizedName":"Deepslate Diamond Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_emerald_ore","localizedName":"Deepslate Emerald Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_gold_ore","localizedName":"Deepslate Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_iron_ore","localizedName":"Deepslate Iron Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_lapis_ore","localizedName":"Deepslate Lapis Lazuli Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_redstone_ore","localizedName":"Deepslate Redstone Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_slab","localizedName":"Deepslate Tile Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_stairs","localizedName":"Deepslate Tile Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_wall","localizedName":"Deepslate Tile Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tiles","localizedName":"Deepslate Tiles","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite","localizedName":"Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dirt","localizedName":"Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dirt_path","localizedName":"Dirt Path","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.65,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.65,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dispenser","localizedName":"Dispenser","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_wall_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dripstone_block","localizedName":"Dripstone Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c3223","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dropper","localizedName":"Dropper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#00d93a","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_gateway","localizedName":"End Gateway","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#191919","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal","localizedName":"End Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#191919","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_rod","localizedName":"End Rod","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_stone","localizedName":"End Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":22.5,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":600.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_chiseled_copper","localizedName":"Exposed Chiseled Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_copper","localizedName":"Exposed Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_copper_bulb","localizedName":"Exposed Copper Bulb","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_copper_door","localizedName":"Exposed Copper Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_copper_grate","localizedName":"Exposed Copper Grate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_copper_trapdoor","localizedName":"Exposed Copper Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper","localizedName":"Exposed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper_slab","localizedName":"Exposed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper_stairs","localizedName":"Exposed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:farmland","localizedName":"Farmland","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fern","localizedName":"Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire","localizedName":"Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#ff0000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_wall_fan","localizedName":"Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flowering_azalea","localizedName":"Flowering Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flowering_azalea_leaves","localizedName":"Flowering Azalea Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:frogspawn","localizedName":"Frogspawn","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:frosted_ice","localizedName":"Frosted Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:furnace","localizedName":"Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:glass","localizedName":"Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glow_lichen","localizedName":"Glow Lichen","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fa796","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.2,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glowstone","localizedName":"Glowstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gold_block","localizedName":"Block of Gold","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#faee4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite","localizedName":"Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:grass_block","localizedName":"Grass Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gravel","localizedName":"Gravel","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_candle","localizedName":"Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_candle_cake","localizedName":"Cake with Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_wall_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_bed","localizedName":"Green Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_candle","localizedName":"Green Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_candle_cake","localizedName":"Cake with Green Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c522a","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_wall_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_wool","localizedName":"Green Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grindstone","localizedName":"Grindstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:hanging_roots","localizedName":"Hanging Roots","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:hay_block","localizedName":"Hay Bale","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:heavy_core","localizedName":"Heavy Core","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":10.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:honey_block","localizedName":"Honey Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:hopper","localizedName":"Hopper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_wall_fan","localizedName":"Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ice","localizedName":"Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_deepslate","localizedName":"Infested Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_block","localizedName":"Block of Iron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_door","localizedName":"Iron Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o\u0027Lantern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jukebox","localizedName":"Jukebox","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_hanging_sign","localizedName":"Jungle Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wall_hanging_sign","localizedName":"Jungle Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wall_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp","localizedName":"Kelp","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp_plant","localizedName":"Kelp Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ladder","localizedName":"Ladder","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lantern","localizedName":"Lantern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_block","localizedName":"Block of Lapis Lazuli","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4a80ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:large_amethyst_bud","localizedName":"Large Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":4,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:large_fern","localizedName":"Large Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lava","localizedName":"Lava","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100.0,"hasContainer":false,"lightValue":15,"liquid":true,"mapColor":"#ff0000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lava_cauldron","localizedName":"Lava Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lectern","localizedName":"Lectern","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lever","localizedName":"Lever","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light","localizedName":"Light","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":3600000.8,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_candle","localizedName":"Light Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_candle_cake","localizedName":"Cake with Light Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#706c8a","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_wall_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_candle","localizedName":"Light Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_candle_cake","localizedName":"Cake with Light Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_wall_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#faee4d","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lightning_rod","localizedName":"Lightning Rod","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lilac","localizedName":"Lilac","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_candle","localizedName":"Lime Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_candle_cake","localizedName":"Cake with Lime Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#677535","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_wall_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lodestone","localizedName":"Lodestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:loom","localizedName":"Loom","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_candle","localizedName":"Magenta Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_candle_cake","localizedName":"Cake with Magenta Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#95576c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_wall_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magma_block","localizedName":"Magma Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":3,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mangrove_button","localizedName":"Mangrove Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_door","localizedName":"Mangrove Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_fence","localizedName":"Mangrove Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_fence_gate","localizedName":"Mangrove Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_hanging_sign","localizedName":"Mangrove Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_leaves","localizedName":"Mangrove Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_log","localizedName":"Mangrove Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_planks","localizedName":"Mangrove Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_pressure_plate","localizedName":"Mangrove Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_propagule","localizedName":"Mangrove Propagule","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_roots","localizedName":"Mangrove Roots","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_sign","localizedName":"Mangrove Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_slab","localizedName":"Mangrove Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_stairs","localizedName":"Mangrove Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_trapdoor","localizedName":"Mangrove Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_wall_hanging_sign","localizedName":"Mangrove Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_wall_sign","localizedName":"Mangrove Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_wood","localizedName":"Mangrove Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:medium_amethyst_bud","localizedName":"Medium Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":2,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:melon","localizedName":"Melon","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:melon_stem","localizedName":"Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:moss_block","localizedName":"Moss Block","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:moss_carpet","localizedName":"Moss Carpet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:moving_piston","localizedName":"Moving Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:mud","localizedName":"Mud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#575c5c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mud_brick_slab","localizedName":"Mud Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mud_brick_stairs","localizedName":"Mud Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mud_brick_wall","localizedName":"Mud Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mud_bricks","localizedName":"Mud Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:muddy_mangrove_roots","localizedName":"Muddy Mangrove Roots","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mycelium","localizedName":"Mycelium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_portal","localizedName":"Nether Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":11,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":true}},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:netherrack","localizedName":"Netherrack","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:note_block","localizedName":"Note Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_button","localizedName":"Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_door","localizedName":"Oak Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_hanging_sign","localizedName":"Oak Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_log","localizedName":"Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wall_hanging_sign","localizedName":"Oak Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wall_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:observer","localizedName":"Observer","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:obsidian","localizedName":"Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:ochre_froglight","localizedName":"Ochre Froglight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_candle","localizedName":"Orange Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_candle_cake","localizedName":"Cake with Orange Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#9f5224","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wall_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oxidized_chiseled_copper","localizedName":"Oxidized Chiseled Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_copper","localizedName":"Oxidized Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_copper_bulb","localizedName":"Oxidized Copper Bulb","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_copper_door","localizedName":"Oxidized Copper Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_copper_grate","localizedName":"Oxidized Copper Grate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_copper_trapdoor","localizedName":"Oxidized Copper Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper","localizedName":"Oxidized Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper_slab","localizedName":"Oxidized Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper_stairs","localizedName":"Oxidized Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:packed_mud","localizedName":"Packed Mud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pearlescent_froglight","localizedName":"Pearlescent Froglight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:peony","localizedName":"Peony","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:piglin_head","localizedName":"Piglin Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:piglin_wall_head","localizedName":"Piglin Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_candle","localizedName":"Pink Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_candle_cake","localizedName":"Cake with Pink Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_petals","localizedName":"Pink Petals","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a04d4e","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wall_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:piston","localizedName":"Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:piston_head","localizedName":"Piston Head","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:pitcher_crop","localizedName":"Pitcher Crop","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pitcher_plant","localizedName":"Pitcher Plant","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:player_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:player_wall_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:podzol","localizedName":"Podzol","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pointed_dripstone","localizedName":"Pointed Dripstone","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c3223","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate","localizedName":"Polished Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_slab","localizedName":"Polished Deepslate Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_stairs","localizedName":"Polished Deepslate Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_wall","localizedName":"Polished Deepslate Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_tuff","localizedName":"Polished Tuff","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_tuff_slab","localizedName":"Polished Tuff Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_tuff_stairs","localizedName":"Polished Tuff Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_tuff_wall","localizedName":"Polished Tuff Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:poppy","localizedName":"Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potatoes","localizedName":"Potatoes","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_acacia_sapling","localizedName":"Potted Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_allium","localizedName":"Potted Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_azalea_bush","localizedName":"Potted Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_azure_bluet","localizedName":"Potted Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_bamboo","localizedName":"Potted Bamboo","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_birch_sapling","localizedName":"Potted Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_blue_orchid","localizedName":"Potted Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_brown_mushroom","localizedName":"Potted Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cactus","localizedName":"Potted Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cherry_sapling","localizedName":"Potted Cherry Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cornflower","localizedName":"Potted Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_fungus","localizedName":"Potted Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_roots","localizedName":"Potted Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dandelion","localizedName":"Potted Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dark_oak_sapling","localizedName":"Potted Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dead_bush","localizedName":"Potted Dead Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_fern","localizedName":"Potted Fern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_flowering_azalea_bush","localizedName":"Potted Flowering Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_jungle_sapling","localizedName":"Potted Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_lily_of_the_valley","localizedName":"Potted Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_mangrove_propagule","localizedName":"Potted Mangrove Propagule","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oak_sapling","localizedName":"Potted Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_orange_tulip","localizedName":"Potted Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oxeye_daisy","localizedName":"Potted Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_pink_tulip","localizedName":"Potted Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_poppy","localizedName":"Potted Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_mushroom","localizedName":"Potted Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_tulip","localizedName":"Potted Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_spruce_sapling","localizedName":"Potted Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_torchflower","localizedName":"Potted Torchflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_fungus","localizedName":"Potted Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_roots","localizedName":"Potted Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_white_tulip","localizedName":"Potted White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_wither_rose","localizedName":"Potted Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:powder_snow","localizedName":"Powder Snow","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.25,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:powder_snow_cauldron","localizedName":"Powder Snow Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:prismarine","localizedName":"Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pumpkin_stem","localizedName":"Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_candle","localizedName":"Purple Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_candle_cake","localizedName":"Cake with Purple Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7a4958","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7a4958","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_wall_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rail","localizedName":"Rail","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:raw_copper_block","localizedName":"Block of Raw Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:raw_gold_block","localizedName":"Block of Raw Gold","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#faee4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:raw_iron_block","localizedName":"Block of Raw Iron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d8af93","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_bed","localizedName":"Red Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_candle","localizedName":"Red Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_candle_cake","localizedName":"Cake with Red Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sand","localizedName":"Red Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8e3c2e","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wall_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wool","localizedName":"Red Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ff0000","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wall_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wire","localizedName":"Redstone Wire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:reinforced_deepslate","localizedName":"Reinforced Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":55.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rooted_dirt","localizedName":"Rooted Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sand","localizedName":"Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sandstone","localizedName":"Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk","localizedName":"Sculk","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_catalyst","localizedName":"Sculk Catalyst","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":6,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_sensor","localizedName":"Sculk Sensor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_shrieker","localizedName":"Sculk Shrieker","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_vein","localizedName":"Sculk Vein","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":6,"liquid":false,"mapColor":"#667f33","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:seagrass","localizedName":"Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:short_grass","localizedName":"Short Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_wall_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:slime_block","localizedName":"Slime Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.8,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:small_amethyst_bud","localizedName":"Small Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:small_dripleaf","localizedName":"Small Dripleaf","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smoker","localizedName":"Smoker","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_basalt","localizedName":"Smooth Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sniffer_egg","localizedName":"Sniffer Egg","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:snow","localizedName":"Snow","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:snow_block","localizedName":"Snow Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":true,"lightValue":10,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_fire","localizedName":"Soul Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#6699d8","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_wall_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spawner","localizedName":"Monster Spawner","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sponge","localizedName":"Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spore_blossom","localizedName":"Spore Blossom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_hanging_sign","localizedName":"Spruce Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wall_hanging_sign","localizedName":"Spruce Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wall_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:stone","localizedName":"Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_button","localizedName":"Stone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_bamboo_block","localizedName":"Block of Stripped Bamboo","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_cherry_log","localizedName":"Stripped Cherry Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_cherry_wood","localizedName":"Stripped Cherry Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a04d4e","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5c191d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_mangrove_log","localizedName":"Stripped Mangrove Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_mangrove_wood","localizedName":"Stripped Mangrove Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#562c3e","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:structure_block","localizedName":"Structure Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:structure_void","localizedName":"Structure Void","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sunflower","localizedName":"Sunflower","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:suspicious_gravel","localizedName":"Suspicious Gravel","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.25,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:suspicious_sand","localizedName":"Suspicious Sand","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.25,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sweet_berry_bush","localizedName":"Sweet Berry Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_seagrass","localizedName":"Tall Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:target","localizedName":"Target","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:terracotta","localizedName":"Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tinted_glass","localizedName":"Tinted Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tnt","localizedName":"TNT","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ff0000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:torchflower","localizedName":"Torchflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:torchflower_crop","localizedName":"Torchflower Crop","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:trial_spawner","localizedName":"Trial Spawner","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":50.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire","localizedName":"Tripwire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_wall_fan","localizedName":"Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tuff","localizedName":"Tuff","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tuff_brick_slab","localizedName":"Tuff Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tuff_brick_stairs","localizedName":"Tuff Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tuff_brick_wall","localizedName":"Tuff Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tuff_bricks","localizedName":"Tuff Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tuff_slab","localizedName":"Tuff Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tuff_stairs","localizedName":"Tuff Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tuff_wall","localizedName":"Tuff Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines_plant","localizedName":"Twisting Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:vault","localizedName":"Vault","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":6,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":50.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:verdant_froglight","localizedName":"Verdant Froglight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#7fa796","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:vine","localizedName":"Vines","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.2,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:void_air","localizedName":"Void Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wall_torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_button","localizedName":"Warped Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_door","localizedName":"Warped Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_hanging_sign","localizedName":"Warped Hanging Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#562c3e","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wall_hanging_sign","localizedName":"Warped Hanging Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wall_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#14b485","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:water","localizedName":"Water","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100.0,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:water_cauldron","localizedName":"Water Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_chiseled_copper","localizedName":"Waxed Chiseled Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_copper_block","localizedName":"Waxed Block of Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_copper_bulb","localizedName":"Waxed Copper Bulb","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_copper_door","localizedName":"Waxed Copper Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_copper_grate","localizedName":"Waxed Copper Grate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_copper_trapdoor","localizedName":"Waxed Copper Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper","localizedName":"Waxed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper_slab","localizedName":"Waxed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper_stairs","localizedName":"Waxed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_chiseled_copper","localizedName":"Waxed Exposed Chiseled Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_copper","localizedName":"Waxed Exposed Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_copper_bulb","localizedName":"Waxed Exposed Copper Bulb","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_copper_door","localizedName":"Waxed Exposed Copper Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_copper_grate","localizedName":"Waxed Exposed Copper Grate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_copper_trapdoor","localizedName":"Waxed Exposed Copper Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper","localizedName":"Waxed Exposed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper_slab","localizedName":"Waxed Exposed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper_stairs","localizedName":"Waxed Exposed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_chiseled_copper","localizedName":"Waxed Oxidized Chiseled Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_copper","localizedName":"Waxed Oxidized Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_copper_bulb","localizedName":"Waxed Oxidized Copper Bulb","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_copper_door","localizedName":"Waxed Oxidized Copper Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_copper_grate","localizedName":"Waxed Oxidized Copper Grate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_copper_trapdoor","localizedName":"Waxed Oxidized Copper Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper","localizedName":"Waxed Oxidized Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper_slab","localizedName":"Waxed Oxidized Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper_stairs","localizedName":"Waxed Oxidized Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_chiseled_copper","localizedName":"Waxed Weathered Chiseled Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_copper","localizedName":"Waxed Weathered Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_copper_bulb","localizedName":"Waxed Weathered Copper Bulb","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_copper_door","localizedName":"Waxed Weathered Copper Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_copper_grate","localizedName":"Waxed Weathered Copper Grate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_copper_trapdoor","localizedName":"Waxed Weathered Copper Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper","localizedName":"Waxed Weathered Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper_slab","localizedName":"Waxed Weathered Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper_stairs","localizedName":"Waxed Weathered Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_chiseled_copper","localizedName":"Weathered Chiseled Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_copper","localizedName":"Weathered Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_copper_bulb","localizedName":"Weathered Copper Bulb","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_copper_door","localizedName":"Weathered Copper Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_copper_grate","localizedName":"Weathered Copper Grate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_copper_trapdoor","localizedName":"Weathered Copper Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper","localizedName":"Weathered Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper_slab","localizedName":"Weathered Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper_stairs","localizedName":"Weathered Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:weeping_vines_plant","localizedName":"Weeping Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wheat","localizedName":"Wheat Crops","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_bed","localizedName":"White Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_candle","localizedName":"White Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_candle_cake","localizedName":"Cake with White Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_carpet","localizedName":"White Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_concrete","localizedName":"White Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_tulip","localizedName":"White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wall_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wool","localizedName":"White Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_wall_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_candle","localizedName":"Yellow Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_candle_cake","localizedName":"Cake with Yellow Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ba8524","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_wall_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_wall_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}}] \ No newline at end of file diff --git a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.1213.json b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.1213.json new file mode 100644 index 000000000..c026d82f0 --- /dev/null +++ b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.1213.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_button","localizedName":"Acacia Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_hanging_sign","localizedName":"Acacia Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wall_hanging_sign","localizedName":"Acacia Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wall_sign","localizedName":"Acacia Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:air","localizedName":"Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:allium","localizedName":"Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:amethyst_block","localizedName":"Block of Amethyst","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:amethyst_cluster","localizedName":"Amethyst Cluster","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":5,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":30.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite","localizedName":"Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:anvil","localizedName":"Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:attached_melon_stem","localizedName":"Attached Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:attached_pumpkin_stem","localizedName":"Attached Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azalea","localizedName":"Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azalea_leaves","localizedName":"Azalea Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo","localizedName":"Bamboo","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_block","localizedName":"Block of Bamboo","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_button","localizedName":"Bamboo Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_door","localizedName":"Bamboo Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_fence","localizedName":"Bamboo Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_fence_gate","localizedName":"Bamboo Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_hanging_sign","localizedName":"Bamboo Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_mosaic","localizedName":"Bamboo Mosaic","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_mosaic_slab","localizedName":"Bamboo Mosaic Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_mosaic_stairs","localizedName":"Bamboo Mosaic Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_planks","localizedName":"Bamboo Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_pressure_plate","localizedName":"Bamboo Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_sapling","localizedName":"Bamboo Shoot","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_sign","localizedName":"Bamboo Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_slab","localizedName":"Bamboo Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_stairs","localizedName":"Bamboo Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_trapdoor","localizedName":"Bamboo Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_wall_hanging_sign","localizedName":"Bamboo Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bamboo_wall_sign","localizedName":"Bamboo Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrel","localizedName":"Barrel","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:barrier","localizedName":"Barrier","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:basalt","localizedName":"Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:beacon","localizedName":"Beacon","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bedrock","localizedName":"Bedrock","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beehive","localizedName":"Beehive","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:beetroots","localizedName":"Beetroots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bell","localizedName":"Bell","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#faee4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:big_dripleaf","localizedName":"Big Dripleaf","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:big_dripleaf_stem","localizedName":"Big Dripleaf Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_button","localizedName":"Birch Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_door","localizedName":"Birch Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_hanging_sign","localizedName":"Birch Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_log","localizedName":"Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wall_hanging_sign","localizedName":"Birch Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wall_sign","localizedName":"Birch Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_bed","localizedName":"Black Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_candle","localizedName":"Black Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_candle_cake","localizedName":"Cake with Black Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#251610","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:black_wall_banner","localizedName":"Black Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:black_wool","localizedName":"Black Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blackstone","localizedName":"Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_candle","localizedName":"Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_candle_cake","localizedName":"Cake with Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.8,"slipperiness":0.989,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c3e5c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:blue_wall_banner","localizedName":"Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bone_block","localizedName":"Bone Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brain_coral_wall_fan","localizedName":"Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":true,"lightValue":1,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bricks","localizedName":"Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_candle","localizedName":"Brown Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_candle_cake","localizedName":"Cake with Brown Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#664c33","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c3223","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:brown_wall_banner","localizedName":"Brown Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_column","localizedName":"Bubble Column","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:bubble_coral_wall_fan","localizedName":"Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:budding_amethyst","localizedName":"Budding Amethyst","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cactus","localizedName":"Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cake","localizedName":"Cake","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:calcite","localizedName":"Calcite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:calibrated_sculk_sensor","localizedName":"Calibrated Sculk Sensor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:campfire","localizedName":"Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":true,"lightValue":15,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:candle","localizedName":"Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:candle_cake","localizedName":"Cake with Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carrots","localizedName":"Carrots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cauldron","localizedName":"Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cave_air","localizedName":"Cave Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cave_vines","localizedName":"Cave Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cave_vines_plant","localizedName":"Cave Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chain","localizedName":"Chain","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cherry_button","localizedName":"Cherry Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_door","localizedName":"Cherry Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_fence","localizedName":"Cherry Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_fence_gate","localizedName":"Cherry Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_hanging_sign","localizedName":"Cherry Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a04d4e","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_leaves","localizedName":"Cherry Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_log","localizedName":"Cherry Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_planks","localizedName":"Cherry Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_pressure_plate","localizedName":"Cherry Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_sapling","localizedName":"Cherry Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_sign","localizedName":"Cherry Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_slab","localizedName":"Cherry Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_stairs","localizedName":"Cherry Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_trapdoor","localizedName":"Cherry Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_wall_hanging_sign","localizedName":"Cherry Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a04d4e","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_wall_sign","localizedName":"Cherry Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cherry_wood","localizedName":"Cherry Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chest","localizedName":"Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:chiseled_bookshelf","localizedName":"Chiseled Bookshelf","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chiseled_copper","localizedName":"Chiseled Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_deepslate","localizedName":"Chiseled Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_tuff","localizedName":"Chiseled Tuff","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chiseled_tuff_bricks","localizedName":"Chiseled Tuff Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:clay","localizedName":"Clay","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:coal_block","localizedName":"Block of Coal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cobbled_deepslate","localizedName":"Cobbled Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_slab","localizedName":"Cobbled Deepslate Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_stairs","localizedName":"Cobbled Deepslate Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobbled_deepslate_wall","localizedName":"Cobbled Deepslate Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cobweb","localizedName":"Cobweb","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":4.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cocoa","localizedName":"Cocoa","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:command_block","localizedName":"Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:composter","localizedName":"Composter","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:conduit","localizedName":"Conduit","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:copper_block","localizedName":"Block of Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:copper_bulb","localizedName":"Copper Bulb","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:copper_door","localizedName":"Copper Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:copper_grate","localizedName":"Copper Grate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:copper_ore","localizedName":"Copper Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:copper_trapdoor","localizedName":"Copper Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cornflower","localizedName":"Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cracked_deepslate_bricks","localizedName":"Cracked Deepslate Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_deepslate_tiles","localizedName":"Cracked Deepslate Tiles","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crafter","localizedName":"Crafter","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creaking_heart","localizedName":"Creaking Heart","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:creeper_wall_head","localizedName":"Creeper Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_hanging_sign","localizedName":"Crimson Hanging Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5c191d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#bd3031","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_wall_hanging_sign","localizedName":"Crimson Hanging Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crimson_wall_sign","localizedName":"Crimson Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper","localizedName":"Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper_slab","localizedName":"Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_copper_stairs","localizedName":"Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_candle","localizedName":"Cyan Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_candle_cake","localizedName":"Cake with Cyan Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#575c5c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:cyan_wall_banner","localizedName":"Cyan Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:dandelion","localizedName":"Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_hanging_sign","localizedName":"Dark Oak Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wall_hanging_sign","localizedName":"Dark Oak Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wall_sign","localizedName":"Dark Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_brain_coral_wall_fan","localizedName":"Dead Brain Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bubble_coral_wall_fan","localizedName":"Dead Bubble Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_fire_coral_wall_fan","localizedName":"Dead Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_horn_coral_wall_fan","localizedName":"Dead Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dead_tube_coral_wall_fan","localizedName":"Dead Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:decorated_pot","localizedName":"Decorated Pot","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8e3c2e","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:deepslate","localizedName":"Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_slab","localizedName":"Deepslate Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_stairs","localizedName":"Deepslate Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_brick_wall","localizedName":"Deepslate Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_bricks","localizedName":"Deepslate Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_coal_ore","localizedName":"Deepslate Coal Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_copper_ore","localizedName":"Deepslate Copper Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_diamond_ore","localizedName":"Deepslate Diamond Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_emerald_ore","localizedName":"Deepslate Emerald Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_gold_ore","localizedName":"Deepslate Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_iron_ore","localizedName":"Deepslate Iron Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_lapis_ore","localizedName":"Deepslate Lapis Lazuli Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_redstone_ore","localizedName":"Deepslate Redstone Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":4.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_slab","localizedName":"Deepslate Tile Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_stairs","localizedName":"Deepslate Tile Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tile_wall","localizedName":"Deepslate Tile Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:deepslate_tiles","localizedName":"Deepslate Tiles","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite","localizedName":"Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dirt","localizedName":"Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dirt_path","localizedName":"Dirt Path","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.65,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.65,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dispenser","localizedName":"Dispenser","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dragon_wall_head","localizedName":"Dragon Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:dripstone_block","localizedName":"Dripstone Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c3223","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:dropper","localizedName":"Dropper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#00d93a","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_gateway","localizedName":"End Gateway","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#191919","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal","localizedName":"End Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#191919","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_rod","localizedName":"End Rod","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:end_stone","localizedName":"End Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":9.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":22.5,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":600.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_chiseled_copper","localizedName":"Exposed Chiseled Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_copper","localizedName":"Exposed Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_copper_bulb","localizedName":"Exposed Copper Bulb","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_copper_door","localizedName":"Exposed Copper Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_copper_grate","localizedName":"Exposed Copper Grate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_copper_trapdoor","localizedName":"Exposed Copper Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper","localizedName":"Exposed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper_slab","localizedName":"Exposed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:exposed_cut_copper_stairs","localizedName":"Exposed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:farmland","localizedName":"Farmland","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fern","localizedName":"Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire","localizedName":"Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#ff0000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fire_coral_wall_fan","localizedName":"Fire Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flowering_azalea","localizedName":"Flowering Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:flowering_azalea_leaves","localizedName":"Flowering Azalea Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:frogspawn","localizedName":"Frogspawn","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:frosted_ice","localizedName":"Frosted Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:furnace","localizedName":"Furnace","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:glass","localizedName":"Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glow_lichen","localizedName":"Glow Lichen","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fa796","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.2,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:glowstone","localizedName":"Glowstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gold_block","localizedName":"Block of Gold","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#faee4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite","localizedName":"Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:grass_block","localizedName":"Grass Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gravel","localizedName":"Gravel","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_candle","localizedName":"Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_candle_cake","localizedName":"Cake with Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:gray_wall_banner","localizedName":"Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_bed","localizedName":"Green Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_candle","localizedName":"Green Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_candle_cake","localizedName":"Cake with Green Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c522a","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:green_wall_banner","localizedName":"Green Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:green_wool","localizedName":"Green Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:grindstone","localizedName":"Grindstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:hanging_roots","localizedName":"Hanging Roots","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:hay_block","localizedName":"Hay Bale","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:heavy_core","localizedName":"Heavy Core","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":10.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:honey_block","localizedName":"Honey Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:hopper","localizedName":"Hopper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:horn_coral_wall_fan","localizedName":"Horn Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ice","localizedName":"Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_deepslate","localizedName":"Infested Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.75,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a4a8b8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.75,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_block","localizedName":"Block of Iron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_door","localizedName":"Iron Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o\u0027Lantern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:jukebox","localizedName":"Jukebox","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_hanging_sign","localizedName":"Jungle Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wall_hanging_sign","localizedName":"Jungle Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wall_sign","localizedName":"Jungle Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp","localizedName":"Kelp","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:kelp_plant","localizedName":"Kelp Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:ladder","localizedName":"Ladder","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lantern","localizedName":"Lantern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_block","localizedName":"Block of Lapis Lazuli","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4a80ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:large_amethyst_bud","localizedName":"Large Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":4,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:large_fern","localizedName":"Large Fern","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lava","localizedName":"Lava","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100.0,"hasContainer":false,"lightValue":15,"liquid":true,"mapColor":"#ff0000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lava_cauldron","localizedName":"Lava Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lectern","localizedName":"Lectern","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lever","localizedName":"Lever","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light","localizedName":"Light","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":3600000.8,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_candle","localizedName":"Light Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_candle_cake","localizedName":"Cake with Light Blue Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#706c8a","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_blue_wall_banner","localizedName":"Light Blue Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#6699d8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_candle","localizedName":"Light Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_candle_cake","localizedName":"Cake with Light Gray Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:light_gray_wall_banner","localizedName":"Light Gray Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#faee4d","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lightning_rod","localizedName":"Lightning Rod","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lilac","localizedName":"Lilac","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_candle","localizedName":"Lime Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_candle_cake","localizedName":"Cake with Lime Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#677535","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:lime_wall_banner","localizedName":"Lime Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:lodestone","localizedName":"Lodestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":true}},{"id":"minecraft:loom","localizedName":"Loom","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_candle","localizedName":"Magenta Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_candle_cake","localizedName":"Cake with Magenta Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#95576c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:magenta_wall_banner","localizedName":"Magenta Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:magma_block","localizedName":"Magma Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":3,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mangrove_button","localizedName":"Mangrove Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_door","localizedName":"Mangrove Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_fence","localizedName":"Mangrove Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_fence_gate","localizedName":"Mangrove Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_hanging_sign","localizedName":"Mangrove Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_leaves","localizedName":"Mangrove Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_log","localizedName":"Mangrove Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_planks","localizedName":"Mangrove Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_pressure_plate","localizedName":"Mangrove Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_propagule","localizedName":"Mangrove Propagule","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_roots","localizedName":"Mangrove Roots","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_sign","localizedName":"Mangrove Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_slab","localizedName":"Mangrove Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_stairs","localizedName":"Mangrove Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_trapdoor","localizedName":"Mangrove Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_wall_hanging_sign","localizedName":"Mangrove Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_wall_sign","localizedName":"Mangrove Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mangrove_wood","localizedName":"Mangrove Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:medium_amethyst_bud","localizedName":"Medium Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":2,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:melon","localizedName":"Melon","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fcc19","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:melon_stem","localizedName":"Melon Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:moss_block","localizedName":"Moss Block","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:moss_carpet","localizedName":"Moss Carpet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#667f33","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:moving_piston","localizedName":"Moving Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:mud","localizedName":"Mud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#575c5c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mud_brick_slab","localizedName":"Mud Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mud_brick_stairs","localizedName":"Mud Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mud_brick_wall","localizedName":"Mud Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:mud_bricks","localizedName":"Mud Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:muddy_mangrove_roots","localizedName":"Muddy Mangrove Roots","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:mycelium","localizedName":"Mycelium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_portal","localizedName":"Nether Portal","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":-1.0,"hasContainer":false,"lightValue":11,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":true}},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:netherrack","localizedName":"Netherrack","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:note_block","localizedName":"Note Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_button","localizedName":"Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_door","localizedName":"Oak Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_hanging_sign","localizedName":"Oak Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_log","localizedName":"Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wall_hanging_sign","localizedName":"Oak Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wall_sign","localizedName":"Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:observer","localizedName":"Observer","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:obsidian","localizedName":"Obsidian","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:ochre_froglight","localizedName":"Ochre Froglight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_candle","localizedName":"Orange Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_candle_cake","localizedName":"Cake with Orange Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#9f5224","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wall_banner","localizedName":"Orange Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:oxidized_chiseled_copper","localizedName":"Oxidized Chiseled Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_copper","localizedName":"Oxidized Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_copper_bulb","localizedName":"Oxidized Copper Bulb","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_copper_door","localizedName":"Oxidized Copper Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_copper_grate","localizedName":"Oxidized Copper Grate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_copper_trapdoor","localizedName":"Oxidized Copper Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper","localizedName":"Oxidized Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper_slab","localizedName":"Oxidized Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:oxidized_cut_copper_stairs","localizedName":"Oxidized Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a0a0ff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.98,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:packed_mud","localizedName":"Packed Mud","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_hanging_moss","localizedName":"Pale Hanging Moss","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_moss_block","localizedName":"Pale Moss Block","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_moss_carpet","localizedName":"Pale Moss Carpet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_oak_button","localizedName":"Pale Oak Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_oak_door","localizedName":"Pale Oak Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_oak_fence","localizedName":"Pale Oak Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_oak_fence_gate","localizedName":"Pale Oak Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_oak_hanging_sign","localizedName":"Pale Oak Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_oak_leaves","localizedName":"Pale Oak Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c522a","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_oak_log","localizedName":"Pale Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_oak_planks","localizedName":"Pale Oak Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_oak_pressure_plate","localizedName":"Pale Oak Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_oak_sapling","localizedName":"Pale Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_oak_sign","localizedName":"Pale Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_oak_slab","localizedName":"Pale Oak Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_oak_stairs","localizedName":"Pale Oak Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_oak_trapdoor","localizedName":"Pale Oak Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_oak_wall_hanging_sign","localizedName":"Pale Oak Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_oak_wall_sign","localizedName":"Pale Oak Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pale_oak_wood","localizedName":"Pale Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pearlescent_froglight","localizedName":"Pearlescent Froglight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:peony","localizedName":"Peony","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:piglin_head","localizedName":"Piglin Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:piglin_wall_head","localizedName":"Piglin Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_candle","localizedName":"Pink Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_candle_cake","localizedName":"Cake with Pink Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_petals","localizedName":"Pink Petals","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a04d4e","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wall_banner","localizedName":"Pink Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f27fa5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:piston","localizedName":"Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:piston_head","localizedName":"Piston Head","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:pitcher_crop","localizedName":"Pitcher Crop","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pitcher_plant","localizedName":"Pitcher Plant","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:player_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:player_wall_head","localizedName":"Player Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:podzol","localizedName":"Podzol","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pointed_dripstone","localizedName":"Pointed Dripstone","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c3223","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate","localizedName":"Polished Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_slab","localizedName":"Polished Deepslate Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_stairs","localizedName":"Polished Deepslate Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_deepslate_wall","localizedName":"Polished Deepslate Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_tuff","localizedName":"Polished Tuff","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_tuff_slab","localizedName":"Polished Tuff Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_tuff_stairs","localizedName":"Polished Tuff Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:polished_tuff_wall","localizedName":"Polished Tuff Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:poppy","localizedName":"Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potatoes","localizedName":"Potatoes","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_acacia_sapling","localizedName":"Potted Acacia Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_allium","localizedName":"Potted Allium","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_azalea_bush","localizedName":"Potted Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_azure_bluet","localizedName":"Potted Azure Bluet","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_bamboo","localizedName":"Potted Bamboo","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_birch_sapling","localizedName":"Potted Birch Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_blue_orchid","localizedName":"Potted Blue Orchid","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_brown_mushroom","localizedName":"Potted Brown Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cactus","localizedName":"Potted Cactus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cherry_sapling","localizedName":"Potted Cherry Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_cornflower","localizedName":"Potted Cornflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_fungus","localizedName":"Potted Crimson Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_crimson_roots","localizedName":"Potted Crimson Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dandelion","localizedName":"Potted Dandelion","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dark_oak_sapling","localizedName":"Potted Dark Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_dead_bush","localizedName":"Potted Dead Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_fern","localizedName":"Potted Fern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_flowering_azalea_bush","localizedName":"Potted Flowering Azalea","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_jungle_sapling","localizedName":"Potted Jungle Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_lily_of_the_valley","localizedName":"Potted Lily of the Valley","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_mangrove_propagule","localizedName":"Potted Mangrove Propagule","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oak_sapling","localizedName":"Potted Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_orange_tulip","localizedName":"Potted Orange Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_oxeye_daisy","localizedName":"Potted Oxeye Daisy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_pale_oak_sapling","localizedName":"Potted Pale Oak Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_pink_tulip","localizedName":"Potted Pink Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_poppy","localizedName":"Potted Poppy","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_mushroom","localizedName":"Potted Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_red_tulip","localizedName":"Potted Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_spruce_sapling","localizedName":"Potted Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_torchflower","localizedName":"Potted Torchflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_fungus","localizedName":"Potted Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_warped_roots","localizedName":"Potted Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_white_tulip","localizedName":"Potted White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:potted_wither_rose","localizedName":"Potted Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:powder_snow","localizedName":"Powder Snow","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.25,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:powder_snow_cauldron","localizedName":"Powder Snow Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:prismarine","localizedName":"Prismarine","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5cdbd5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:pumpkin_stem","localizedName":"Pumpkin Stem","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_candle","localizedName":"Purple Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_candle_cake","localizedName":"Cake with Purple Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7a4958","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7a4958","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purple_wall_banner","localizedName":"Purple Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#b24cd8","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rail","localizedName":"Rail","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.7,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.7,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:raw_copper_block","localizedName":"Block of Raw Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:raw_gold_block","localizedName":"Block of Raw Gold","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#faee4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:raw_iron_block","localizedName":"Block of Raw Iron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d8af93","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_bed","localizedName":"Red Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_candle","localizedName":"Red Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_candle_cake","localizedName":"Cake with Red Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sand","localizedName":"Red Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8e3c2e","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wall_banner","localizedName":"Red Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:red_wool","localizedName":"Red Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ff0000","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#9f5224","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wall_torch","localizedName":"Redstone Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":7,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:redstone_wire","localizedName":"Redstone Wire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:reinforced_deepslate","localizedName":"Reinforced Deepslate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":55.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#646464","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1200.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:rooted_dirt","localizedName":"Rooted Dirt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sand","localizedName":"Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sandstone","localizedName":"Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk","localizedName":"Sculk","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_catalyst","localizedName":"Sculk Catalyst","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":6,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_sensor","localizedName":"Sculk Sensor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#4c7f99","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_shrieker","localizedName":"Sculk Shrieker","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sculk_vein","localizedName":"Sculk Vein","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":6,"liquid":false,"mapColor":"#667f33","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:seagrass","localizedName":"Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:short_grass","localizedName":"Short Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:skeleton_wall_skull","localizedName":"Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:slime_block","localizedName":"Slime Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#7fb238","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.8,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:small_amethyst_bud","localizedName":"Small Amethyst Bud","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":1,"liquid":false,"mapColor":"#7f3fb2","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:small_dripleaf","localizedName":"Small Dripleaf","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:smoker","localizedName":"Smoker","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_basalt","localizedName":"Smooth Basalt","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#191919","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sniffer_egg","localizedName":"Sniffer Egg","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:snow","localizedName":"Snow","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:snow_block","localizedName":"Snow Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":true,"lightValue":10,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_fire","localizedName":"Soul Fire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#6699d8","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#a7a7a7","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:soul_wall_torch","localizedName":"Soul Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":10,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spawner","localizedName":"Monster Spawner","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":5.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":5.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:sponge","localizedName":"Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spore_blossom","localizedName":"Spore Blossom","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_hanging_sign","localizedName":"Spruce Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":true,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wall_hanging_sign","localizedName":"Spruce Hanging Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wall_sign","localizedName":"Spruce Sign","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":true}},{"id":"minecraft:stone","localizedName":"Stone","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_button","localizedName":"Stone Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_bamboo_block","localizedName":"Block of Stripped Bamboo","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_cherry_log","localizedName":"Stripped Cherry Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_cherry_wood","localizedName":"Stripped Cherry Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#a04d4e","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#5c191d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#943f61","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#664c33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#976d4d","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_mangrove_log","localizedName":"Stripped Mangrove Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_mangrove_wood","localizedName":"Stripped Mangrove Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#993333","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_pale_oak_log","localizedName":"Stripped Pale Oak Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_pale_oak_wood","localizedName":"Stripped Pale Oak Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#815631","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#562c3e","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:structure_block","localizedName":"Structure Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":-1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#999999","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3600000.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:structure_void","localizedName":"Structure Void","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sunflower","localizedName":"Sunflower","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:suspicious_gravel","localizedName":"Suspicious Gravel","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.25,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:suspicious_sand","localizedName":"Suspicious Sand","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":0.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.25,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:sweet_berry_bush","localizedName":"Sweet Berry Bush","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tall_seagrass","localizedName":"Tall Seagrass","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:target","localizedName":"Target","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#fffcf5","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:terracotta","localizedName":"Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tinted_glass","localizedName":"Tinted Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c4c4c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tnt","localizedName":"TNT","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ff0000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:torchflower","localizedName":"Torchflower","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:torchflower_crop","localizedName":"Torchflower Crop","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":2.5,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":true,"powerSource":true,"replacedDuringPlacement":false,"resistance":2.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:trial_spawner","localizedName":"Trial Spawner","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":50.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire","localizedName":"Tripwire","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tube_coral_wall_fan","localizedName":"Tube Coral Wall Fan","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#334cb2","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:tuff","localizedName":"Tuff","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tuff_brick_slab","localizedName":"Tuff Brick Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tuff_brick_stairs","localizedName":"Tuff Brick Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tuff_brick_wall","localizedName":"Tuff Brick Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tuff_bricks","localizedName":"Tuff Bricks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tuff_slab","localizedName":"Tuff Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tuff_stairs","localizedName":"Tuff Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:tuff_wall","localizedName":"Tuff Wall","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#392923","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#f7e9a3","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:twisting_vines_plant","localizedName":"Twisting Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:vault","localizedName":"Vault","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":50.0,"hasContainer":false,"lightValue":6,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":50.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:verdant_froglight","localizedName":"Verdant Froglight","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":15,"liquid":false,"mapColor":"#7fa796","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:vine","localizedName":"Vines","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.2,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:void_air","localizedName":"Void Air","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wall_torch","localizedName":"Torch","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":14,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_button","localizedName":"Warped Button","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_door","localizedName":"Warped Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_hanging_sign","localizedName":"Warped Hanging Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#562c3e","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.4,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":true,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#4c7f99","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":3.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wall_hanging_sign","localizedName":"Warped Hanging Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wall_sign","localizedName":"Warped Sign","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#14b485","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:water","localizedName":"Water","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":100.0,"hasContainer":false,"lightValue":0,"liquid":true,"mapColor":"#4040ff","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":true,"resistance":100.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:water_cauldron","localizedName":"Water Cauldron","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":2.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#707070","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_chiseled_copper","localizedName":"Waxed Chiseled Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_copper_block","localizedName":"Waxed Block of Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_copper_bulb","localizedName":"Waxed Copper Bulb","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_copper_door","localizedName":"Waxed Copper Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_copper_grate","localizedName":"Waxed Copper Grate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_copper_trapdoor","localizedName":"Waxed Copper Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper","localizedName":"Waxed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper_slab","localizedName":"Waxed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_cut_copper_stairs","localizedName":"Waxed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d87f33","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_chiseled_copper","localizedName":"Waxed Exposed Chiseled Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_copper","localizedName":"Waxed Exposed Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_copper_bulb","localizedName":"Waxed Exposed Copper Bulb","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_copper_door","localizedName":"Waxed Exposed Copper Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_copper_grate","localizedName":"Waxed Exposed Copper Grate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_copper_trapdoor","localizedName":"Waxed Exposed Copper Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper","localizedName":"Waxed Exposed Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper_slab","localizedName":"Waxed Exposed Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_exposed_cut_copper_stairs","localizedName":"Waxed Exposed Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#876b62","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_chiseled_copper","localizedName":"Waxed Oxidized Chiseled Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_copper","localizedName":"Waxed Oxidized Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_copper_bulb","localizedName":"Waxed Oxidized Copper Bulb","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_copper_door","localizedName":"Waxed Oxidized Copper Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_copper_grate","localizedName":"Waxed Oxidized Copper Grate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_copper_trapdoor","localizedName":"Waxed Oxidized Copper Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper","localizedName":"Waxed Oxidized Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper_slab","localizedName":"Waxed Oxidized Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_oxidized_cut_copper_stairs","localizedName":"Waxed Oxidized Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#167e86","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_chiseled_copper","localizedName":"Waxed Weathered Chiseled Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_copper","localizedName":"Waxed Weathered Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_copper_bulb","localizedName":"Waxed Weathered Copper Bulb","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_copper_door","localizedName":"Waxed Weathered Copper Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_copper_grate","localizedName":"Waxed Weathered Copper Grate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_copper_trapdoor","localizedName":"Waxed Weathered Copper Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper","localizedName":"Waxed Weathered Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper_slab","localizedName":"Waxed Weathered Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:waxed_weathered_cut_copper_stairs","localizedName":"Waxed Weathered Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_chiseled_copper","localizedName":"Weathered Chiseled Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_copper","localizedName":"Weathered Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_copper_bulb","localizedName":"Weathered Copper Bulb","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_copper_door","localizedName":"Weathered Copper Door","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_copper_grate","localizedName":"Weathered Copper Grate","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_copper_trapdoor","localizedName":"Weathered Copper Trapdoor","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper","localizedName":"Weathered Cut Copper","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper_slab","localizedName":"Weathered Cut Copper Slab","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weathered_cut_copper_stairs","localizedName":"Weathered Cut Copper Stairs","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":3.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#3a8e8c","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":6.0,"slipperiness":0.6,"solid":true,"ticksRandomly":true,"toolRequired":true,"unpushable":false}},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:weeping_vines_plant","localizedName":"Weeping Vines Plant","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#700200","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.6,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.6,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wheat","localizedName":"Wheat Crops","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":true,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_bed","localizedName":"White Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_candle","localizedName":"White Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#c7c7c7","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_candle_cake","localizedName":"Cake with White Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_carpet","localizedName":"White Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_concrete","localizedName":"White Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#d1b1a1","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:white_tulip","localizedName":"White Tulip","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wall_banner","localizedName":"White Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:white_wool","localizedName":"White Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ffffff","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#007c00","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:wither_skeleton_wall_skull","localizedName":"Wither Skeleton Skull","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","material":{"burnable":true,"fragileWhenPushed":true,"fullCube":false,"hardness":0.2,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_candle","localizedName":"Yellow Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":false,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_candle_cake","localizedName":"Cake with Yellow Candle","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":0.1,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.1,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.5,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.5,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.4,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.4,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":true,"hardness":2.0,"hasContainer":true,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":2.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":false,"hardness":0.3,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.3,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","material":{"burnable":false,"fragileWhenPushed":false,"fullCube":true,"hardness":1.25,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#ba8524","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":4.2,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":true,"unpushable":false}},{"id":"minecraft:yellow_wall_banner","localizedName":"Yellow Banner","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#8f7748","movementBlocker":true,"opaque":false,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","material":{"burnable":true,"fragileWhenPushed":false,"fullCube":true,"hardness":0.8,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#e5e533","movementBlocker":true,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":0.8,"slipperiness":0.6,"solid":true,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}},{"id":"minecraft:zombie_wall_head","localizedName":"Zombie Head","material":{"burnable":false,"fragileWhenPushed":true,"fullCube":false,"hardness":1.0,"hasContainer":false,"lightValue":0,"liquid":false,"mapColor":"#000000","movementBlocker":false,"opaque":true,"powerSource":false,"replacedDuringPlacement":false,"resistance":1.0,"slipperiness":0.6,"solid":false,"ticksRandomly":false,"toolRequired":false,"unpushable":false}}] diff --git a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.115.json b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.115.json deleted file mode 100644 index 77b94c077..000000000 --- a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.115.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":"minecraft:acacia_boat","unlocalizedName":"item.minecraft.acacia_boat","localizedName":"Acacia Boat","maxDamage":0,"maxStackSize":1},{"id":"minecraft:acacia_button","unlocalizedName":"block.minecraft.acacia_button","localizedName":"Acacia Button","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_door","unlocalizedName":"block.minecraft.acacia_door","localizedName":"Acacia Door","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_fence","unlocalizedName":"block.minecraft.acacia_fence","localizedName":"Acacia Fence","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_fence_gate","unlocalizedName":"block.minecraft.acacia_fence_gate","localizedName":"Acacia Fence Gate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_leaves","unlocalizedName":"block.minecraft.acacia_leaves","localizedName":"Acacia Leaves","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_log","unlocalizedName":"block.minecraft.acacia_log","localizedName":"Acacia Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_planks","unlocalizedName":"block.minecraft.acacia_planks","localizedName":"Acacia Planks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_pressure_plate","unlocalizedName":"block.minecraft.acacia_pressure_plate","localizedName":"Acacia Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_sapling","unlocalizedName":"block.minecraft.acacia_sapling","localizedName":"Acacia Sapling","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_sign","unlocalizedName":"block.minecraft.acacia_sign","localizedName":"Acacia Sign","maxDamage":0,"maxStackSize":16},{"id":"minecraft:acacia_slab","unlocalizedName":"block.minecraft.acacia_slab","localizedName":"Acacia Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_stairs","unlocalizedName":"block.minecraft.acacia_stairs","localizedName":"Acacia Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_trapdoor","unlocalizedName":"block.minecraft.acacia_trapdoor","localizedName":"Acacia Trapdoor","maxDamage":0,"maxStackSize":64},{"id":"minecraft:acacia_wood","unlocalizedName":"block.minecraft.acacia_wood","localizedName":"Acacia Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:activator_rail","unlocalizedName":"block.minecraft.activator_rail","localizedName":"Activator Rail","maxDamage":0,"maxStackSize":64},{"id":"minecraft:air","unlocalizedName":"block.minecraft.air","localizedName":"Air","maxDamage":0,"maxStackSize":64},{"id":"minecraft:allium","unlocalizedName":"block.minecraft.allium","localizedName":"Allium","maxDamage":0,"maxStackSize":64},{"id":"minecraft:andesite","unlocalizedName":"block.minecraft.andesite","localizedName":"Andesite","maxDamage":0,"maxStackSize":64},{"id":"minecraft:andesite_slab","unlocalizedName":"block.minecraft.andesite_slab","localizedName":"Andesite Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:andesite_stairs","unlocalizedName":"block.minecraft.andesite_stairs","localizedName":"Andesite Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:andesite_wall","unlocalizedName":"block.minecraft.andesite_wall","localizedName":"Andesite Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:anvil","unlocalizedName":"block.minecraft.anvil","localizedName":"Anvil","maxDamage":0,"maxStackSize":64},{"id":"minecraft:apple","unlocalizedName":"item.minecraft.apple","localizedName":"Apple","maxDamage":0,"maxStackSize":64},{"id":"minecraft:armor_stand","unlocalizedName":"item.minecraft.armor_stand","localizedName":"Armor Stand","maxDamage":0,"maxStackSize":16},{"id":"minecraft:arrow","unlocalizedName":"item.minecraft.arrow","localizedName":"Arrow","maxDamage":0,"maxStackSize":64},{"id":"minecraft:azure_bluet","unlocalizedName":"block.minecraft.azure_bluet","localizedName":"Azure Bluet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:baked_potato","unlocalizedName":"item.minecraft.baked_potato","localizedName":"Baked Potato","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bamboo","unlocalizedName":"block.minecraft.bamboo","localizedName":"Bamboo","maxDamage":0,"maxStackSize":64},{"id":"minecraft:barrel","unlocalizedName":"block.minecraft.barrel","localizedName":"Barrel","maxDamage":0,"maxStackSize":64},{"id":"minecraft:barrier","unlocalizedName":"block.minecraft.barrier","localizedName":"Barrier","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bat_spawn_egg","unlocalizedName":"item.minecraft.bat_spawn_egg","localizedName":"Bat Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:beacon","unlocalizedName":"block.minecraft.beacon","localizedName":"Beacon","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bedrock","unlocalizedName":"block.minecraft.bedrock","localizedName":"Bedrock","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bee_nest","unlocalizedName":"block.minecraft.bee_nest","localizedName":"Bee Nest","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bee_spawn_egg","unlocalizedName":"item.minecraft.bee_spawn_egg","localizedName":"Bee Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:beef","unlocalizedName":"item.minecraft.beef","localizedName":"Raw Beef","maxDamage":0,"maxStackSize":64},{"id":"minecraft:beehive","unlocalizedName":"block.minecraft.beehive","localizedName":"Beehive","maxDamage":0,"maxStackSize":64},{"id":"minecraft:beetroot","unlocalizedName":"item.minecraft.beetroot","localizedName":"Beetroot","maxDamage":0,"maxStackSize":64},{"id":"minecraft:beetroot_seeds","unlocalizedName":"item.minecraft.beetroot_seeds","localizedName":"Beetroot Seeds","maxDamage":0,"maxStackSize":64},{"id":"minecraft:beetroot_soup","unlocalizedName":"item.minecraft.beetroot_soup","localizedName":"Beetroot Soup","maxDamage":0,"maxStackSize":1},{"id":"minecraft:bell","unlocalizedName":"block.minecraft.bell","localizedName":"Bell","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_boat","unlocalizedName":"item.minecraft.birch_boat","localizedName":"Birch Boat","maxDamage":0,"maxStackSize":1},{"id":"minecraft:birch_button","unlocalizedName":"block.minecraft.birch_button","localizedName":"Birch Button","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_door","unlocalizedName":"block.minecraft.birch_door","localizedName":"Birch Door","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_fence","unlocalizedName":"block.minecraft.birch_fence","localizedName":"Birch Fence","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_fence_gate","unlocalizedName":"block.minecraft.birch_fence_gate","localizedName":"Birch Fence Gate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_leaves","unlocalizedName":"block.minecraft.birch_leaves","localizedName":"Birch Leaves","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_log","unlocalizedName":"block.minecraft.birch_log","localizedName":"Birch Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_planks","unlocalizedName":"block.minecraft.birch_planks","localizedName":"Birch Planks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_pressure_plate","unlocalizedName":"block.minecraft.birch_pressure_plate","localizedName":"Birch Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_sapling","unlocalizedName":"block.minecraft.birch_sapling","localizedName":"Birch Sapling","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_sign","unlocalizedName":"block.minecraft.birch_sign","localizedName":"Birch Sign","maxDamage":0,"maxStackSize":16},{"id":"minecraft:birch_slab","unlocalizedName":"block.minecraft.birch_slab","localizedName":"Birch Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_stairs","unlocalizedName":"block.minecraft.birch_stairs","localizedName":"Birch Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_trapdoor","unlocalizedName":"block.minecraft.birch_trapdoor","localizedName":"Birch Trapdoor","maxDamage":0,"maxStackSize":64},{"id":"minecraft:birch_wood","unlocalizedName":"block.minecraft.birch_wood","localizedName":"Birch Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_banner","unlocalizedName":"block.minecraft.black_banner","localizedName":"Black Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:black_bed","unlocalizedName":"block.minecraft.black_bed","localizedName":"Black Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:black_carpet","unlocalizedName":"block.minecraft.black_carpet","localizedName":"Black Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_concrete","unlocalizedName":"block.minecraft.black_concrete","localizedName":"Black Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_concrete_powder","unlocalizedName":"block.minecraft.black_concrete_powder","localizedName":"Black Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_dye","unlocalizedName":"item.minecraft.black_dye","localizedName":"Black Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_glazed_terracotta","unlocalizedName":"block.minecraft.black_glazed_terracotta","localizedName":"Black Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_shulker_box","unlocalizedName":"block.minecraft.black_shulker_box","localizedName":"Black Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:black_stained_glass","unlocalizedName":"block.minecraft.black_stained_glass","localizedName":"Black Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_stained_glass_pane","unlocalizedName":"block.minecraft.black_stained_glass_pane","localizedName":"Black Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_terracotta","unlocalizedName":"block.minecraft.black_terracotta","localizedName":"Black Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:black_wool","unlocalizedName":"block.minecraft.black_wool","localizedName":"Black Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blast_furnace","unlocalizedName":"block.minecraft.blast_furnace","localizedName":"Blast Furnace","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blaze_powder","unlocalizedName":"item.minecraft.blaze_powder","localizedName":"Blaze Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blaze_rod","unlocalizedName":"item.minecraft.blaze_rod","localizedName":"Blaze Rod","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blaze_spawn_egg","unlocalizedName":"item.minecraft.blaze_spawn_egg","localizedName":"Blaze Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_banner","unlocalizedName":"block.minecraft.blue_banner","localizedName":"Blue Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:blue_bed","unlocalizedName":"block.minecraft.blue_bed","localizedName":"Blue Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:blue_carpet","unlocalizedName":"block.minecraft.blue_carpet","localizedName":"Blue Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_concrete","unlocalizedName":"block.minecraft.blue_concrete","localizedName":"Blue Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_concrete_powder","unlocalizedName":"block.minecraft.blue_concrete_powder","localizedName":"Blue Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_dye","unlocalizedName":"item.minecraft.blue_dye","localizedName":"Blue Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_glazed_terracotta","unlocalizedName":"block.minecraft.blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_ice","unlocalizedName":"block.minecraft.blue_ice","localizedName":"Blue Ice","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_orchid","unlocalizedName":"block.minecraft.blue_orchid","localizedName":"Blue Orchid","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_shulker_box","unlocalizedName":"block.minecraft.blue_shulker_box","localizedName":"Blue Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:blue_stained_glass","unlocalizedName":"block.minecraft.blue_stained_glass","localizedName":"Blue Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_stained_glass_pane","unlocalizedName":"block.minecraft.blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_terracotta","unlocalizedName":"block.minecraft.blue_terracotta","localizedName":"Blue Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:blue_wool","unlocalizedName":"block.minecraft.blue_wool","localizedName":"Blue Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bone","unlocalizedName":"item.minecraft.bone","localizedName":"Bone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bone_block","unlocalizedName":"block.minecraft.bone_block","localizedName":"Bone Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bone_meal","unlocalizedName":"item.minecraft.bone_meal","localizedName":"Bone Meal","maxDamage":0,"maxStackSize":64},{"id":"minecraft:book","unlocalizedName":"item.minecraft.book","localizedName":"Book","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bookshelf","unlocalizedName":"block.minecraft.bookshelf","localizedName":"Bookshelf","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bow","unlocalizedName":"item.minecraft.bow","localizedName":"Bow","maxDamage":384,"maxStackSize":1},{"id":"minecraft:bowl","unlocalizedName":"item.minecraft.bowl","localizedName":"Bowl","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brain_coral","unlocalizedName":"block.minecraft.brain_coral","localizedName":"Brain Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brain_coral_block","unlocalizedName":"block.minecraft.brain_coral_block","localizedName":"Brain Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brain_coral_fan","unlocalizedName":"block.minecraft.brain_coral_fan","localizedName":"Brain Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bread","unlocalizedName":"item.minecraft.bread","localizedName":"Bread","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brewing_stand","unlocalizedName":"block.minecraft.brewing_stand","localizedName":"Brewing Stand","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brick","unlocalizedName":"item.minecraft.brick","localizedName":"Brick","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brick_slab","unlocalizedName":"block.minecraft.brick_slab","localizedName":"Brick Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brick_stairs","unlocalizedName":"block.minecraft.brick_stairs","localizedName":"Brick Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brick_wall","unlocalizedName":"block.minecraft.brick_wall","localizedName":"Brick Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bricks","unlocalizedName":"block.minecraft.bricks","localizedName":"Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_banner","unlocalizedName":"block.minecraft.brown_banner","localizedName":"Brown Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:brown_bed","unlocalizedName":"block.minecraft.brown_bed","localizedName":"Brown Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:brown_carpet","unlocalizedName":"block.minecraft.brown_carpet","localizedName":"Brown Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_concrete","unlocalizedName":"block.minecraft.brown_concrete","localizedName":"Brown Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_concrete_powder","unlocalizedName":"block.minecraft.brown_concrete_powder","localizedName":"Brown Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_dye","unlocalizedName":"item.minecraft.brown_dye","localizedName":"Brown Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_glazed_terracotta","unlocalizedName":"block.minecraft.brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_mushroom","unlocalizedName":"block.minecraft.brown_mushroom","localizedName":"Brown Mushroom","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_mushroom_block","unlocalizedName":"block.minecraft.brown_mushroom_block","localizedName":"Brown Mushroom Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_shulker_box","unlocalizedName":"block.minecraft.brown_shulker_box","localizedName":"Brown Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:brown_stained_glass","unlocalizedName":"block.minecraft.brown_stained_glass","localizedName":"Brown Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_stained_glass_pane","unlocalizedName":"block.minecraft.brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_terracotta","unlocalizedName":"block.minecraft.brown_terracotta","localizedName":"Brown Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:brown_wool","unlocalizedName":"block.minecraft.brown_wool","localizedName":"Brown Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bubble_coral","unlocalizedName":"block.minecraft.bubble_coral","localizedName":"Bubble Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bubble_coral_block","unlocalizedName":"block.minecraft.bubble_coral_block","localizedName":"Bubble Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bubble_coral_fan","unlocalizedName":"block.minecraft.bubble_coral_fan","localizedName":"Bubble Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:bucket","unlocalizedName":"item.minecraft.bucket","localizedName":"Bucket","maxDamage":0,"maxStackSize":16},{"id":"minecraft:cactus","unlocalizedName":"block.minecraft.cactus","localizedName":"Cactus","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cake","unlocalizedName":"block.minecraft.cake","localizedName":"Cake","maxDamage":0,"maxStackSize":1},{"id":"minecraft:campfire","unlocalizedName":"block.minecraft.campfire","localizedName":"Campfire","maxDamage":0,"maxStackSize":64},{"id":"minecraft:carrot","unlocalizedName":"item.minecraft.carrot","localizedName":"Carrot","maxDamage":0,"maxStackSize":64},{"id":"minecraft:carrot_on_a_stick","unlocalizedName":"item.minecraft.carrot_on_a_stick","localizedName":"Carrot on a Stick","maxDamage":25,"maxStackSize":1},{"id":"minecraft:cartography_table","unlocalizedName":"block.minecraft.cartography_table","localizedName":"Cartography Table","maxDamage":0,"maxStackSize":64},{"id":"minecraft:carved_pumpkin","unlocalizedName":"block.minecraft.carved_pumpkin","localizedName":"Carved Pumpkin","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cat_spawn_egg","unlocalizedName":"item.minecraft.cat_spawn_egg","localizedName":"Cat Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cauldron","unlocalizedName":"block.minecraft.cauldron","localizedName":"Cauldron","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cave_spider_spawn_egg","unlocalizedName":"item.minecraft.cave_spider_spawn_egg","localizedName":"Cave Spider Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chain_command_block","unlocalizedName":"block.minecraft.chain_command_block","localizedName":"Chain Command Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chainmail_boots","unlocalizedName":"item.minecraft.chainmail_boots","localizedName":"Chainmail Boots","maxDamage":195,"maxStackSize":1},{"id":"minecraft:chainmail_chestplate","unlocalizedName":"item.minecraft.chainmail_chestplate","localizedName":"Chainmail Chestplate","maxDamage":240,"maxStackSize":1},{"id":"minecraft:chainmail_helmet","unlocalizedName":"item.minecraft.chainmail_helmet","localizedName":"Chainmail Helmet","maxDamage":165,"maxStackSize":1},{"id":"minecraft:chainmail_leggings","unlocalizedName":"item.minecraft.chainmail_leggings","localizedName":"Chainmail Leggings","maxDamage":225,"maxStackSize":1},{"id":"minecraft:charcoal","unlocalizedName":"item.minecraft.charcoal","localizedName":"Charcoal","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chest","unlocalizedName":"block.minecraft.chest","localizedName":"Chest","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chest_minecart","unlocalizedName":"item.minecraft.chest_minecart","localizedName":"Minecart with Chest","maxDamage":0,"maxStackSize":1},{"id":"minecraft:chicken","unlocalizedName":"item.minecraft.chicken","localizedName":"Raw Chicken","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chicken_spawn_egg","unlocalizedName":"item.minecraft.chicken_spawn_egg","localizedName":"Chicken Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chipped_anvil","unlocalizedName":"block.minecraft.chipped_anvil","localizedName":"Chipped Anvil","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chiseled_quartz_block","unlocalizedName":"block.minecraft.chiseled_quartz_block","localizedName":"Chiseled Quartz Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chiseled_red_sandstone","unlocalizedName":"block.minecraft.chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chiseled_sandstone","unlocalizedName":"block.minecraft.chiseled_sandstone","localizedName":"Chiseled Sandstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chiseled_stone_bricks","unlocalizedName":"block.minecraft.chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chorus_flower","unlocalizedName":"block.minecraft.chorus_flower","localizedName":"Chorus Flower","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chorus_fruit","unlocalizedName":"item.minecraft.chorus_fruit","localizedName":"Chorus Fruit","maxDamage":0,"maxStackSize":64},{"id":"minecraft:chorus_plant","unlocalizedName":"block.minecraft.chorus_plant","localizedName":"Chorus Plant","maxDamage":0,"maxStackSize":64},{"id":"minecraft:clay","unlocalizedName":"block.minecraft.clay","localizedName":"Clay","maxDamage":0,"maxStackSize":64},{"id":"minecraft:clay_ball","unlocalizedName":"item.minecraft.clay_ball","localizedName":"Clay","maxDamage":0,"maxStackSize":64},{"id":"minecraft:clock","unlocalizedName":"item.minecraft.clock","localizedName":"Clock","maxDamage":0,"maxStackSize":64},{"id":"minecraft:coal","unlocalizedName":"item.minecraft.coal","localizedName":"Coal","maxDamage":0,"maxStackSize":64},{"id":"minecraft:coal_block","unlocalizedName":"block.minecraft.coal_block","localizedName":"Block of Coal","maxDamage":0,"maxStackSize":64},{"id":"minecraft:coal_ore","unlocalizedName":"block.minecraft.coal_ore","localizedName":"Coal Ore","maxDamage":0,"maxStackSize":64},{"id":"minecraft:coarse_dirt","unlocalizedName":"block.minecraft.coarse_dirt","localizedName":"Coarse Dirt","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cobblestone","unlocalizedName":"block.minecraft.cobblestone","localizedName":"Cobblestone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cobblestone_slab","unlocalizedName":"block.minecraft.cobblestone_slab","localizedName":"Cobblestone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cobblestone_stairs","unlocalizedName":"block.minecraft.cobblestone_stairs","localizedName":"Cobblestone Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cobblestone_wall","unlocalizedName":"block.minecraft.cobblestone_wall","localizedName":"Cobblestone Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cobweb","unlocalizedName":"block.minecraft.cobweb","localizedName":"Cobweb","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cocoa_beans","unlocalizedName":"item.minecraft.cocoa_beans","localizedName":"Cocoa Beans","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cod","unlocalizedName":"item.minecraft.cod","localizedName":"Raw Cod","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cod_bucket","unlocalizedName":"item.minecraft.cod_bucket","localizedName":"Bucket of Cod","maxDamage":0,"maxStackSize":1},{"id":"minecraft:cod_spawn_egg","unlocalizedName":"item.minecraft.cod_spawn_egg","localizedName":"Cod Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:command_block","unlocalizedName":"block.minecraft.command_block","localizedName":"Command Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:command_block_minecart","unlocalizedName":"item.minecraft.command_block_minecart","localizedName":"Minecart with Command Block","maxDamage":0,"maxStackSize":1},{"id":"minecraft:comparator","unlocalizedName":"block.minecraft.comparator","localizedName":"Redstone Comparator","maxDamage":0,"maxStackSize":64},{"id":"minecraft:compass","unlocalizedName":"item.minecraft.compass","localizedName":"Compass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:composter","unlocalizedName":"block.minecraft.composter","localizedName":"Composter","maxDamage":0,"maxStackSize":64},{"id":"minecraft:conduit","unlocalizedName":"block.minecraft.conduit","localizedName":"Conduit","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cooked_beef","unlocalizedName":"item.minecraft.cooked_beef","localizedName":"Steak","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cooked_chicken","unlocalizedName":"item.minecraft.cooked_chicken","localizedName":"Cooked Chicken","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cooked_cod","unlocalizedName":"item.minecraft.cooked_cod","localizedName":"Cooked Cod","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cooked_mutton","unlocalizedName":"item.minecraft.cooked_mutton","localizedName":"Cooked Mutton","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cooked_porkchop","unlocalizedName":"item.minecraft.cooked_porkchop","localizedName":"Cooked Porkchop","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cooked_rabbit","unlocalizedName":"item.minecraft.cooked_rabbit","localizedName":"Cooked Rabbit","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cooked_salmon","unlocalizedName":"item.minecraft.cooked_salmon","localizedName":"Cooked Salmon","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cookie","unlocalizedName":"item.minecraft.cookie","localizedName":"Cookie","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cornflower","unlocalizedName":"block.minecraft.cornflower","localizedName":"Cornflower","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cow_spawn_egg","unlocalizedName":"item.minecraft.cow_spawn_egg","localizedName":"Cow Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cracked_stone_bricks","unlocalizedName":"block.minecraft.cracked_stone_bricks","localizedName":"Cracked Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:crafting_table","unlocalizedName":"block.minecraft.crafting_table","localizedName":"Crafting Table","maxDamage":0,"maxStackSize":64},{"id":"minecraft:creeper_banner_pattern","unlocalizedName":"item.minecraft.creeper_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1},{"id":"minecraft:creeper_head","unlocalizedName":"block.minecraft.creeper_head","localizedName":"Creeper Head","maxDamage":0,"maxStackSize":64},{"id":"minecraft:creeper_spawn_egg","unlocalizedName":"item.minecraft.creeper_spawn_egg","localizedName":"Creeper Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:crossbow","unlocalizedName":"item.minecraft.crossbow","localizedName":"Crossbow","maxDamage":326,"maxStackSize":1},{"id":"minecraft:cut_red_sandstone","unlocalizedName":"block.minecraft.cut_red_sandstone","localizedName":"Cut Red Sandstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cut_red_sandstone_slab","unlocalizedName":"block.minecraft.cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cut_sandstone","unlocalizedName":"block.minecraft.cut_sandstone","localizedName":"Cut Sandstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cut_sandstone_slab","unlocalizedName":"block.minecraft.cut_sandstone_slab","localizedName":"Cut Sandstone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_banner","unlocalizedName":"block.minecraft.cyan_banner","localizedName":"Cyan Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:cyan_bed","unlocalizedName":"block.minecraft.cyan_bed","localizedName":"Cyan Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:cyan_carpet","unlocalizedName":"block.minecraft.cyan_carpet","localizedName":"Cyan Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_concrete","unlocalizedName":"block.minecraft.cyan_concrete","localizedName":"Cyan Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_concrete_powder","unlocalizedName":"block.minecraft.cyan_concrete_powder","localizedName":"Cyan Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_dye","unlocalizedName":"item.minecraft.cyan_dye","localizedName":"Cyan Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_glazed_terracotta","unlocalizedName":"block.minecraft.cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_shulker_box","unlocalizedName":"block.minecraft.cyan_shulker_box","localizedName":"Cyan Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:cyan_stained_glass","unlocalizedName":"block.minecraft.cyan_stained_glass","localizedName":"Cyan Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_stained_glass_pane","unlocalizedName":"block.minecraft.cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_terracotta","unlocalizedName":"block.minecraft.cyan_terracotta","localizedName":"Cyan Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:cyan_wool","unlocalizedName":"block.minecraft.cyan_wool","localizedName":"Cyan Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:damaged_anvil","unlocalizedName":"block.minecraft.damaged_anvil","localizedName":"Damaged Anvil","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dandelion","unlocalizedName":"block.minecraft.dandelion","localizedName":"Dandelion","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_boat","unlocalizedName":"item.minecraft.dark_oak_boat","localizedName":"Dark Oak Boat","maxDamage":0,"maxStackSize":1},{"id":"minecraft:dark_oak_button","unlocalizedName":"block.minecraft.dark_oak_button","localizedName":"Dark Oak Button","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_door","unlocalizedName":"block.minecraft.dark_oak_door","localizedName":"Dark Oak Door","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_fence","unlocalizedName":"block.minecraft.dark_oak_fence","localizedName":"Dark Oak Fence","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_fence_gate","unlocalizedName":"block.minecraft.dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_leaves","unlocalizedName":"block.minecraft.dark_oak_leaves","localizedName":"Dark Oak Leaves","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_log","unlocalizedName":"block.minecraft.dark_oak_log","localizedName":"Dark Oak Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_planks","unlocalizedName":"block.minecraft.dark_oak_planks","localizedName":"Dark Oak Planks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_pressure_plate","unlocalizedName":"block.minecraft.dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_sapling","unlocalizedName":"block.minecraft.dark_oak_sapling","localizedName":"Dark Oak Sapling","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_sign","unlocalizedName":"block.minecraft.dark_oak_sign","localizedName":"Dark Oak Sign","maxDamage":0,"maxStackSize":16},{"id":"minecraft:dark_oak_slab","unlocalizedName":"block.minecraft.dark_oak_slab","localizedName":"Dark Oak Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_stairs","unlocalizedName":"block.minecraft.dark_oak_stairs","localizedName":"Dark Oak Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_trapdoor","unlocalizedName":"block.minecraft.dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_oak_wood","unlocalizedName":"block.minecraft.dark_oak_wood","localizedName":"Dark Oak Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_prismarine","unlocalizedName":"block.minecraft.dark_prismarine","localizedName":"Dark Prismarine","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_prismarine_slab","unlocalizedName":"block.minecraft.dark_prismarine_slab","localizedName":"Dark Prismarine Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dark_prismarine_stairs","unlocalizedName":"block.minecraft.dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:daylight_detector","unlocalizedName":"block.minecraft.daylight_detector","localizedName":"Daylight Detector","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_brain_coral","unlocalizedName":"block.minecraft.dead_brain_coral","localizedName":"Dead Brain Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_brain_coral_block","unlocalizedName":"block.minecraft.dead_brain_coral_block","localizedName":"Dead Brain Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_brain_coral_fan","unlocalizedName":"block.minecraft.dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_bubble_coral","unlocalizedName":"block.minecraft.dead_bubble_coral","localizedName":"Dead Bubble Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_bubble_coral_block","unlocalizedName":"block.minecraft.dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_bubble_coral_fan","unlocalizedName":"block.minecraft.dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_bush","unlocalizedName":"block.minecraft.dead_bush","localizedName":"Dead Bush","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_fire_coral","unlocalizedName":"block.minecraft.dead_fire_coral","localizedName":"Dead Fire Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_fire_coral_block","unlocalizedName":"block.minecraft.dead_fire_coral_block","localizedName":"Dead Fire Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_fire_coral_fan","unlocalizedName":"block.minecraft.dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_horn_coral","unlocalizedName":"block.minecraft.dead_horn_coral","localizedName":"Dead Horn Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_horn_coral_block","unlocalizedName":"block.minecraft.dead_horn_coral_block","localizedName":"Dead Horn Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_horn_coral_fan","unlocalizedName":"block.minecraft.dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_tube_coral","unlocalizedName":"block.minecraft.dead_tube_coral","localizedName":"Dead Tube Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_tube_coral_block","unlocalizedName":"block.minecraft.dead_tube_coral_block","localizedName":"Dead Tube Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dead_tube_coral_fan","unlocalizedName":"block.minecraft.dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:debug_stick","unlocalizedName":"item.minecraft.debug_stick","localizedName":"Debug Stick","maxDamage":0,"maxStackSize":1},{"id":"minecraft:detector_rail","unlocalizedName":"block.minecraft.detector_rail","localizedName":"Detector Rail","maxDamage":0,"maxStackSize":64},{"id":"minecraft:diamond","unlocalizedName":"item.minecraft.diamond","localizedName":"Diamond","maxDamage":0,"maxStackSize":64},{"id":"minecraft:diamond_axe","unlocalizedName":"item.minecraft.diamond_axe","localizedName":"Diamond Axe","maxDamage":1561,"maxStackSize":1},{"id":"minecraft:diamond_block","unlocalizedName":"block.minecraft.diamond_block","localizedName":"Block of Diamond","maxDamage":0,"maxStackSize":64},{"id":"minecraft:diamond_boots","unlocalizedName":"item.minecraft.diamond_boots","localizedName":"Diamond Boots","maxDamage":429,"maxStackSize":1},{"id":"minecraft:diamond_chestplate","unlocalizedName":"item.minecraft.diamond_chestplate","localizedName":"Diamond Chestplate","maxDamage":528,"maxStackSize":1},{"id":"minecraft:diamond_helmet","unlocalizedName":"item.minecraft.diamond_helmet","localizedName":"Diamond Helmet","maxDamage":363,"maxStackSize":1},{"id":"minecraft:diamond_hoe","unlocalizedName":"item.minecraft.diamond_hoe","localizedName":"Diamond Hoe","maxDamage":1561,"maxStackSize":1},{"id":"minecraft:diamond_horse_armor","unlocalizedName":"item.minecraft.diamond_horse_armor","localizedName":"Diamond Horse Armor","maxDamage":0,"maxStackSize":1},{"id":"minecraft:diamond_leggings","unlocalizedName":"item.minecraft.diamond_leggings","localizedName":"Diamond Leggings","maxDamage":495,"maxStackSize":1},{"id":"minecraft:diamond_ore","unlocalizedName":"block.minecraft.diamond_ore","localizedName":"Diamond Ore","maxDamage":0,"maxStackSize":64},{"id":"minecraft:diamond_pickaxe","unlocalizedName":"item.minecraft.diamond_pickaxe","localizedName":"Diamond Pickaxe","maxDamage":1561,"maxStackSize":1},{"id":"minecraft:diamond_shovel","unlocalizedName":"item.minecraft.diamond_shovel","localizedName":"Diamond Shovel","maxDamage":1561,"maxStackSize":1},{"id":"minecraft:diamond_sword","unlocalizedName":"item.minecraft.diamond_sword","localizedName":"Diamond Sword","maxDamage":1561,"maxStackSize":1},{"id":"minecraft:diorite","unlocalizedName":"block.minecraft.diorite","localizedName":"Diorite","maxDamage":0,"maxStackSize":64},{"id":"minecraft:diorite_slab","unlocalizedName":"block.minecraft.diorite_slab","localizedName":"Diorite Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:diorite_stairs","unlocalizedName":"block.minecraft.diorite_stairs","localizedName":"Diorite Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:diorite_wall","unlocalizedName":"block.minecraft.diorite_wall","localizedName":"Diorite Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dirt","unlocalizedName":"block.minecraft.dirt","localizedName":"Dirt","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dispenser","unlocalizedName":"block.minecraft.dispenser","localizedName":"Dispenser","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dolphin_spawn_egg","unlocalizedName":"item.minecraft.dolphin_spawn_egg","localizedName":"Dolphin Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:donkey_spawn_egg","unlocalizedName":"item.minecraft.donkey_spawn_egg","localizedName":"Donkey Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dragon_breath","unlocalizedName":"item.minecraft.dragon_breath","localizedName":"Dragon's Breath","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dragon_egg","unlocalizedName":"block.minecraft.dragon_egg","localizedName":"Dragon Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dragon_head","unlocalizedName":"block.minecraft.dragon_head","localizedName":"Dragon Head","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dried_kelp","unlocalizedName":"item.minecraft.dried_kelp","localizedName":"Dried Kelp","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dried_kelp_block","unlocalizedName":"block.minecraft.dried_kelp_block","localizedName":"Dried Kelp Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:dropper","unlocalizedName":"block.minecraft.dropper","localizedName":"Dropper","maxDamage":0,"maxStackSize":64},{"id":"minecraft:drowned_spawn_egg","unlocalizedName":"item.minecraft.drowned_spawn_egg","localizedName":"Drowned Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:egg","unlocalizedName":"item.minecraft.egg","localizedName":"Egg","maxDamage":0,"maxStackSize":16},{"id":"minecraft:elder_guardian_spawn_egg","unlocalizedName":"item.minecraft.elder_guardian_spawn_egg","localizedName":"Elder Guardian Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:elytra","unlocalizedName":"item.minecraft.elytra","localizedName":"Elytra","maxDamage":432,"maxStackSize":1},{"id":"minecraft:emerald","unlocalizedName":"item.minecraft.emerald","localizedName":"Emerald","maxDamage":0,"maxStackSize":64},{"id":"minecraft:emerald_block","unlocalizedName":"block.minecraft.emerald_block","localizedName":"Block of Emerald","maxDamage":0,"maxStackSize":64},{"id":"minecraft:emerald_ore","unlocalizedName":"block.minecraft.emerald_ore","localizedName":"Emerald Ore","maxDamage":0,"maxStackSize":64},{"id":"minecraft:enchanted_book","unlocalizedName":"item.minecraft.enchanted_book","localizedName":"Enchanted Book","maxDamage":0,"maxStackSize":1},{"id":"minecraft:enchanted_golden_apple","unlocalizedName":"item.minecraft.enchanted_golden_apple","localizedName":"Enchanted Golden Apple","maxDamage":0,"maxStackSize":64},{"id":"minecraft:enchanting_table","unlocalizedName":"block.minecraft.enchanting_table","localizedName":"Enchanting Table","maxDamage":0,"maxStackSize":64},{"id":"minecraft:end_crystal","unlocalizedName":"item.minecraft.end_crystal","localizedName":"End Crystal","maxDamage":0,"maxStackSize":64},{"id":"minecraft:end_portal_frame","unlocalizedName":"block.minecraft.end_portal_frame","localizedName":"End Portal Frame","maxDamage":0,"maxStackSize":64},{"id":"minecraft:end_rod","unlocalizedName":"block.minecraft.end_rod","localizedName":"End Rod","maxDamage":0,"maxStackSize":64},{"id":"minecraft:end_stone","unlocalizedName":"block.minecraft.end_stone","localizedName":"End Stone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:end_stone_brick_slab","unlocalizedName":"block.minecraft.end_stone_brick_slab","localizedName":"End Stone Brick Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:end_stone_brick_stairs","unlocalizedName":"block.minecraft.end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:end_stone_brick_wall","unlocalizedName":"block.minecraft.end_stone_brick_wall","localizedName":"End Stone Brick Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:end_stone_bricks","unlocalizedName":"block.minecraft.end_stone_bricks","localizedName":"End Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:ender_chest","unlocalizedName":"block.minecraft.ender_chest","localizedName":"Ender Chest","maxDamage":0,"maxStackSize":64},{"id":"minecraft:ender_eye","unlocalizedName":"item.minecraft.ender_eye","localizedName":"Eye of Ender","maxDamage":0,"maxStackSize":64},{"id":"minecraft:ender_pearl","unlocalizedName":"item.minecraft.ender_pearl","localizedName":"Ender Pearl","maxDamage":0,"maxStackSize":16},{"id":"minecraft:enderman_spawn_egg","unlocalizedName":"item.minecraft.enderman_spawn_egg","localizedName":"Enderman Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:endermite_spawn_egg","unlocalizedName":"item.minecraft.endermite_spawn_egg","localizedName":"Endermite Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:evoker_spawn_egg","unlocalizedName":"item.minecraft.evoker_spawn_egg","localizedName":"Evoker Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:experience_bottle","unlocalizedName":"item.minecraft.experience_bottle","localizedName":"Bottle o' Enchanting","maxDamage":0,"maxStackSize":64},{"id":"minecraft:farmland","unlocalizedName":"block.minecraft.farmland","localizedName":"Farmland","maxDamage":0,"maxStackSize":64},{"id":"minecraft:feather","unlocalizedName":"item.minecraft.feather","localizedName":"Feather","maxDamage":0,"maxStackSize":64},{"id":"minecraft:fermented_spider_eye","unlocalizedName":"item.minecraft.fermented_spider_eye","localizedName":"Fermented Spider Eye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:fern","unlocalizedName":"block.minecraft.fern","localizedName":"Fern","maxDamage":0,"maxStackSize":64},{"id":"minecraft:filled_map","unlocalizedName":"item.minecraft.filled_map","localizedName":"Map","maxDamage":0,"maxStackSize":64},{"id":"minecraft:fire_charge","unlocalizedName":"item.minecraft.fire_charge","localizedName":"Fire Charge","maxDamage":0,"maxStackSize":64},{"id":"minecraft:fire_coral","unlocalizedName":"block.minecraft.fire_coral","localizedName":"Fire Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:fire_coral_block","unlocalizedName":"block.minecraft.fire_coral_block","localizedName":"Fire Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:fire_coral_fan","unlocalizedName":"block.minecraft.fire_coral_fan","localizedName":"Fire Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:firework_rocket","unlocalizedName":"item.minecraft.firework_rocket","localizedName":"Firework Rocket","maxDamage":0,"maxStackSize":64},{"id":"minecraft:firework_star","unlocalizedName":"item.minecraft.firework_star","localizedName":"Firework Star","maxDamage":0,"maxStackSize":64},{"id":"minecraft:fishing_rod","unlocalizedName":"item.minecraft.fishing_rod","localizedName":"Fishing Rod","maxDamage":64,"maxStackSize":1},{"id":"minecraft:fletching_table","unlocalizedName":"block.minecraft.fletching_table","localizedName":"Fletching Table","maxDamage":0,"maxStackSize":64},{"id":"minecraft:flint","unlocalizedName":"item.minecraft.flint","localizedName":"Flint","maxDamage":0,"maxStackSize":64},{"id":"minecraft:flint_and_steel","unlocalizedName":"item.minecraft.flint_and_steel","localizedName":"Flint and Steel","maxDamage":64,"maxStackSize":1},{"id":"minecraft:flower_banner_pattern","unlocalizedName":"item.minecraft.flower_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1},{"id":"minecraft:flower_pot","unlocalizedName":"block.minecraft.flower_pot","localizedName":"Flower Pot","maxDamage":0,"maxStackSize":64},{"id":"minecraft:fox_spawn_egg","unlocalizedName":"item.minecraft.fox_spawn_egg","localizedName":"Fox Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:furnace","unlocalizedName":"block.minecraft.furnace","localizedName":"Furnace","maxDamage":0,"maxStackSize":64},{"id":"minecraft:furnace_minecart","unlocalizedName":"item.minecraft.furnace_minecart","localizedName":"Minecart with Furnace","maxDamage":0,"maxStackSize":1},{"id":"minecraft:ghast_spawn_egg","unlocalizedName":"item.minecraft.ghast_spawn_egg","localizedName":"Ghast Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:ghast_tear","unlocalizedName":"item.minecraft.ghast_tear","localizedName":"Ghast Tear","maxDamage":0,"maxStackSize":64},{"id":"minecraft:glass","unlocalizedName":"block.minecraft.glass","localizedName":"Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:glass_bottle","unlocalizedName":"item.minecraft.glass_bottle","localizedName":"Glass Bottle","maxDamage":0,"maxStackSize":64},{"id":"minecraft:glass_pane","unlocalizedName":"block.minecraft.glass_pane","localizedName":"Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:glistering_melon_slice","unlocalizedName":"item.minecraft.glistering_melon_slice","localizedName":"Glistering Melon Slice","maxDamage":0,"maxStackSize":64},{"id":"minecraft:globe_banner_pattern","unlocalizedName":"item.minecraft.globe_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1},{"id":"minecraft:glowstone","unlocalizedName":"block.minecraft.glowstone","localizedName":"Glowstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:glowstone_dust","unlocalizedName":"item.minecraft.glowstone_dust","localizedName":"Glowstone Dust","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gold_block","unlocalizedName":"block.minecraft.gold_block","localizedName":"Block of Gold","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gold_ingot","unlocalizedName":"item.minecraft.gold_ingot","localizedName":"Gold Ingot","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gold_nugget","unlocalizedName":"item.minecraft.gold_nugget","localizedName":"Gold Nugget","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gold_ore","unlocalizedName":"block.minecraft.gold_ore","localizedName":"Gold Ore","maxDamage":0,"maxStackSize":64},{"id":"minecraft:golden_apple","unlocalizedName":"item.minecraft.golden_apple","localizedName":"Golden Apple","maxDamage":0,"maxStackSize":64},{"id":"minecraft:golden_axe","unlocalizedName":"item.minecraft.golden_axe","localizedName":"Golden Axe","maxDamage":32,"maxStackSize":1},{"id":"minecraft:golden_boots","unlocalizedName":"item.minecraft.golden_boots","localizedName":"Golden Boots","maxDamage":91,"maxStackSize":1},{"id":"minecraft:golden_carrot","unlocalizedName":"item.minecraft.golden_carrot","localizedName":"Golden Carrot","maxDamage":0,"maxStackSize":64},{"id":"minecraft:golden_chestplate","unlocalizedName":"item.minecraft.golden_chestplate","localizedName":"Golden Chestplate","maxDamage":112,"maxStackSize":1},{"id":"minecraft:golden_helmet","unlocalizedName":"item.minecraft.golden_helmet","localizedName":"Golden Helmet","maxDamage":77,"maxStackSize":1},{"id":"minecraft:golden_hoe","unlocalizedName":"item.minecraft.golden_hoe","localizedName":"Golden Hoe","maxDamage":32,"maxStackSize":1},{"id":"minecraft:golden_horse_armor","unlocalizedName":"item.minecraft.golden_horse_armor","localizedName":"Golden Horse Armor","maxDamage":0,"maxStackSize":1},{"id":"minecraft:golden_leggings","unlocalizedName":"item.minecraft.golden_leggings","localizedName":"Golden Leggings","maxDamage":105,"maxStackSize":1},{"id":"minecraft:golden_pickaxe","unlocalizedName":"item.minecraft.golden_pickaxe","localizedName":"Golden Pickaxe","maxDamage":32,"maxStackSize":1},{"id":"minecraft:golden_shovel","unlocalizedName":"item.minecraft.golden_shovel","localizedName":"Golden Shovel","maxDamage":32,"maxStackSize":1},{"id":"minecraft:golden_sword","unlocalizedName":"item.minecraft.golden_sword","localizedName":"Golden Sword","maxDamage":32,"maxStackSize":1},{"id":"minecraft:granite","unlocalizedName":"block.minecraft.granite","localizedName":"Granite","maxDamage":0,"maxStackSize":64},{"id":"minecraft:granite_slab","unlocalizedName":"block.minecraft.granite_slab","localizedName":"Granite Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:granite_stairs","unlocalizedName":"block.minecraft.granite_stairs","localizedName":"Granite Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:granite_wall","unlocalizedName":"block.minecraft.granite_wall","localizedName":"Granite Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:grass","unlocalizedName":"block.minecraft.grass","localizedName":"Grass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:grass_block","unlocalizedName":"block.minecraft.grass_block","localizedName":"Grass Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:grass_path","unlocalizedName":"block.minecraft.grass_path","localizedName":"Grass Path","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gravel","unlocalizedName":"block.minecraft.gravel","localizedName":"Gravel","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_banner","unlocalizedName":"block.minecraft.gray_banner","localizedName":"Gray Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:gray_bed","unlocalizedName":"block.minecraft.gray_bed","localizedName":"Gray Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:gray_carpet","unlocalizedName":"block.minecraft.gray_carpet","localizedName":"Gray Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_concrete","unlocalizedName":"block.minecraft.gray_concrete","localizedName":"Gray Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_concrete_powder","unlocalizedName":"block.minecraft.gray_concrete_powder","localizedName":"Gray Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_dye","unlocalizedName":"item.minecraft.gray_dye","localizedName":"Gray Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_glazed_terracotta","unlocalizedName":"block.minecraft.gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_shulker_box","unlocalizedName":"block.minecraft.gray_shulker_box","localizedName":"Gray Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:gray_stained_glass","unlocalizedName":"block.minecraft.gray_stained_glass","localizedName":"Gray Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_stained_glass_pane","unlocalizedName":"block.minecraft.gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_terracotta","unlocalizedName":"block.minecraft.gray_terracotta","localizedName":"Gray Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gray_wool","unlocalizedName":"block.minecraft.gray_wool","localizedName":"Gray Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_banner","unlocalizedName":"block.minecraft.green_banner","localizedName":"Green Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:green_bed","unlocalizedName":"block.minecraft.green_bed","localizedName":"Green Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:green_carpet","unlocalizedName":"block.minecraft.green_carpet","localizedName":"Green Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_concrete","unlocalizedName":"block.minecraft.green_concrete","localizedName":"Green Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_concrete_powder","unlocalizedName":"block.minecraft.green_concrete_powder","localizedName":"Green Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_dye","unlocalizedName":"item.minecraft.green_dye","localizedName":"Green Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_glazed_terracotta","unlocalizedName":"block.minecraft.green_glazed_terracotta","localizedName":"Green Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_shulker_box","unlocalizedName":"block.minecraft.green_shulker_box","localizedName":"Green Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:green_stained_glass","unlocalizedName":"block.minecraft.green_stained_glass","localizedName":"Green Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_stained_glass_pane","unlocalizedName":"block.minecraft.green_stained_glass_pane","localizedName":"Green Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_terracotta","unlocalizedName":"block.minecraft.green_terracotta","localizedName":"Green Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:green_wool","unlocalizedName":"block.minecraft.green_wool","localizedName":"Green Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:grindstone","unlocalizedName":"block.minecraft.grindstone","localizedName":"Grindstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:guardian_spawn_egg","unlocalizedName":"item.minecraft.guardian_spawn_egg","localizedName":"Guardian Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:gunpowder","unlocalizedName":"item.minecraft.gunpowder","localizedName":"Gunpowder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:hay_block","unlocalizedName":"block.minecraft.hay_block","localizedName":"Hay Bale","maxDamage":0,"maxStackSize":64},{"id":"minecraft:heart_of_the_sea","unlocalizedName":"item.minecraft.heart_of_the_sea","localizedName":"Heart of the Sea","maxDamage":0,"maxStackSize":64},{"id":"minecraft:heavy_weighted_pressure_plate","unlocalizedName":"block.minecraft.heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:honey_block","unlocalizedName":"block.minecraft.honey_block","localizedName":"Honey Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:honey_bottle","unlocalizedName":"item.minecraft.honey_bottle","localizedName":"Honey Bottle","maxDamage":0,"maxStackSize":16},{"id":"minecraft:honeycomb","unlocalizedName":"item.minecraft.honeycomb","localizedName":"Honeycomb","maxDamage":0,"maxStackSize":64},{"id":"minecraft:honeycomb_block","unlocalizedName":"block.minecraft.honeycomb_block","localizedName":"Honeycomb Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:hopper","unlocalizedName":"block.minecraft.hopper","localizedName":"Hopper","maxDamage":0,"maxStackSize":64},{"id":"minecraft:hopper_minecart","unlocalizedName":"item.minecraft.hopper_minecart","localizedName":"Minecart with Hopper","maxDamage":0,"maxStackSize":1},{"id":"minecraft:horn_coral","unlocalizedName":"block.minecraft.horn_coral","localizedName":"Horn Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:horn_coral_block","unlocalizedName":"block.minecraft.horn_coral_block","localizedName":"Horn Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:horn_coral_fan","unlocalizedName":"block.minecraft.horn_coral_fan","localizedName":"Horn Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:horse_spawn_egg","unlocalizedName":"item.minecraft.horse_spawn_egg","localizedName":"Horse Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:husk_spawn_egg","unlocalizedName":"item.minecraft.husk_spawn_egg","localizedName":"Husk Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:ice","unlocalizedName":"block.minecraft.ice","localizedName":"Ice","maxDamage":0,"maxStackSize":64},{"id":"minecraft:infested_chiseled_stone_bricks","unlocalizedName":"block.minecraft.infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:infested_cobblestone","unlocalizedName":"block.minecraft.infested_cobblestone","localizedName":"Infested Cobblestone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:infested_cracked_stone_bricks","unlocalizedName":"block.minecraft.infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:infested_mossy_stone_bricks","unlocalizedName":"block.minecraft.infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:infested_stone","unlocalizedName":"block.minecraft.infested_stone","localizedName":"Infested Stone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:infested_stone_bricks","unlocalizedName":"block.minecraft.infested_stone_bricks","localizedName":"Infested Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:ink_sac","unlocalizedName":"item.minecraft.ink_sac","localizedName":"Ink Sac","maxDamage":0,"maxStackSize":64},{"id":"minecraft:iron_axe","unlocalizedName":"item.minecraft.iron_axe","localizedName":"Iron Axe","maxDamage":250,"maxStackSize":1},{"id":"minecraft:iron_bars","unlocalizedName":"block.minecraft.iron_bars","localizedName":"Iron Bars","maxDamage":0,"maxStackSize":64},{"id":"minecraft:iron_block","unlocalizedName":"block.minecraft.iron_block","localizedName":"Block of Iron","maxDamage":0,"maxStackSize":64},{"id":"minecraft:iron_boots","unlocalizedName":"item.minecraft.iron_boots","localizedName":"Iron Boots","maxDamage":195,"maxStackSize":1},{"id":"minecraft:iron_chestplate","unlocalizedName":"item.minecraft.iron_chestplate","localizedName":"Iron Chestplate","maxDamage":240,"maxStackSize":1},{"id":"minecraft:iron_door","unlocalizedName":"block.minecraft.iron_door","localizedName":"Iron Door","maxDamage":0,"maxStackSize":64},{"id":"minecraft:iron_helmet","unlocalizedName":"item.minecraft.iron_helmet","localizedName":"Iron Helmet","maxDamage":165,"maxStackSize":1},{"id":"minecraft:iron_hoe","unlocalizedName":"item.minecraft.iron_hoe","localizedName":"Iron Hoe","maxDamage":250,"maxStackSize":1},{"id":"minecraft:iron_horse_armor","unlocalizedName":"item.minecraft.iron_horse_armor","localizedName":"Iron Horse Armor","maxDamage":0,"maxStackSize":1},{"id":"minecraft:iron_ingot","unlocalizedName":"item.minecraft.iron_ingot","localizedName":"Iron Ingot","maxDamage":0,"maxStackSize":64},{"id":"minecraft:iron_leggings","unlocalizedName":"item.minecraft.iron_leggings","localizedName":"Iron Leggings","maxDamage":225,"maxStackSize":1},{"id":"minecraft:iron_nugget","unlocalizedName":"item.minecraft.iron_nugget","localizedName":"Iron Nugget","maxDamage":0,"maxStackSize":64},{"id":"minecraft:iron_ore","unlocalizedName":"block.minecraft.iron_ore","localizedName":"Iron Ore","maxDamage":0,"maxStackSize":64},{"id":"minecraft:iron_pickaxe","unlocalizedName":"item.minecraft.iron_pickaxe","localizedName":"Iron Pickaxe","maxDamage":250,"maxStackSize":1},{"id":"minecraft:iron_shovel","unlocalizedName":"item.minecraft.iron_shovel","localizedName":"Iron Shovel","maxDamage":250,"maxStackSize":1},{"id":"minecraft:iron_sword","unlocalizedName":"item.minecraft.iron_sword","localizedName":"Iron Sword","maxDamage":250,"maxStackSize":1},{"id":"minecraft:iron_trapdoor","unlocalizedName":"block.minecraft.iron_trapdoor","localizedName":"Iron Trapdoor","maxDamage":0,"maxStackSize":64},{"id":"minecraft:item_frame","unlocalizedName":"item.minecraft.item_frame","localizedName":"Item Frame","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jack_o_lantern","unlocalizedName":"block.minecraft.jack_o_lantern","localizedName":"Jack o'Lantern","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jigsaw","unlocalizedName":"block.minecraft.jigsaw","localizedName":"Jigsaw Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jukebox","unlocalizedName":"block.minecraft.jukebox","localizedName":"Jukebox","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_boat","unlocalizedName":"item.minecraft.jungle_boat","localizedName":"Jungle Boat","maxDamage":0,"maxStackSize":1},{"id":"minecraft:jungle_button","unlocalizedName":"block.minecraft.jungle_button","localizedName":"Jungle Button","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_door","unlocalizedName":"block.minecraft.jungle_door","localizedName":"Jungle Door","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_fence","unlocalizedName":"block.minecraft.jungle_fence","localizedName":"Jungle Fence","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_fence_gate","unlocalizedName":"block.minecraft.jungle_fence_gate","localizedName":"Jungle Fence Gate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_leaves","unlocalizedName":"block.minecraft.jungle_leaves","localizedName":"Jungle Leaves","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_log","unlocalizedName":"block.minecraft.jungle_log","localizedName":"Jungle Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_planks","unlocalizedName":"block.minecraft.jungle_planks","localizedName":"Jungle Planks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_pressure_plate","unlocalizedName":"block.minecraft.jungle_pressure_plate","localizedName":"Jungle Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_sapling","unlocalizedName":"block.minecraft.jungle_sapling","localizedName":"Jungle Sapling","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_sign","unlocalizedName":"block.minecraft.jungle_sign","localizedName":"Jungle Sign","maxDamage":0,"maxStackSize":16},{"id":"minecraft:jungle_slab","unlocalizedName":"block.minecraft.jungle_slab","localizedName":"Jungle Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_stairs","unlocalizedName":"block.minecraft.jungle_stairs","localizedName":"Jungle Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_trapdoor","unlocalizedName":"block.minecraft.jungle_trapdoor","localizedName":"Jungle Trapdoor","maxDamage":0,"maxStackSize":64},{"id":"minecraft:jungle_wood","unlocalizedName":"block.minecraft.jungle_wood","localizedName":"Jungle Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:kelp","unlocalizedName":"block.minecraft.kelp","localizedName":"Kelp","maxDamage":0,"maxStackSize":64},{"id":"minecraft:knowledge_book","unlocalizedName":"item.minecraft.knowledge_book","localizedName":"Knowledge Book","maxDamage":0,"maxStackSize":1},{"id":"minecraft:ladder","unlocalizedName":"block.minecraft.ladder","localizedName":"Ladder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lantern","unlocalizedName":"block.minecraft.lantern","localizedName":"Lantern","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lapis_block","unlocalizedName":"block.minecraft.lapis_block","localizedName":"Lapis Lazuli Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lapis_lazuli","unlocalizedName":"item.minecraft.lapis_lazuli","localizedName":"Lapis Lazuli","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lapis_ore","unlocalizedName":"block.minecraft.lapis_ore","localizedName":"Lapis Lazuli Ore","maxDamage":0,"maxStackSize":64},{"id":"minecraft:large_fern","unlocalizedName":"block.minecraft.large_fern","localizedName":"Large Fern","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lava_bucket","unlocalizedName":"item.minecraft.lava_bucket","localizedName":"Lava Bucket","maxDamage":0,"maxStackSize":1},{"id":"minecraft:lead","unlocalizedName":"item.minecraft.lead","localizedName":"Lead","maxDamage":0,"maxStackSize":64},{"id":"minecraft:leather","unlocalizedName":"item.minecraft.leather","localizedName":"Leather","maxDamage":0,"maxStackSize":64},{"id":"minecraft:leather_boots","unlocalizedName":"item.minecraft.leather_boots","localizedName":"Leather Boots","maxDamage":65,"maxStackSize":1},{"id":"minecraft:leather_chestplate","unlocalizedName":"item.minecraft.leather_chestplate","localizedName":"Leather Tunic","maxDamage":80,"maxStackSize":1},{"id":"minecraft:leather_helmet","unlocalizedName":"item.minecraft.leather_helmet","localizedName":"Leather Cap","maxDamage":55,"maxStackSize":1},{"id":"minecraft:leather_horse_armor","unlocalizedName":"item.minecraft.leather_horse_armor","localizedName":"Leather Horse Armor","maxDamage":0,"maxStackSize":1},{"id":"minecraft:leather_leggings","unlocalizedName":"item.minecraft.leather_leggings","localizedName":"Leather Pants","maxDamage":75,"maxStackSize":1},{"id":"minecraft:lectern","unlocalizedName":"block.minecraft.lectern","localizedName":"Lectern","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lever","unlocalizedName":"block.minecraft.lever","localizedName":"Lever","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_banner","unlocalizedName":"block.minecraft.light_blue_banner","localizedName":"Light Blue Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:light_blue_bed","unlocalizedName":"block.minecraft.light_blue_bed","localizedName":"Light Blue Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:light_blue_carpet","unlocalizedName":"block.minecraft.light_blue_carpet","localizedName":"Light Blue Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_concrete","unlocalizedName":"block.minecraft.light_blue_concrete","localizedName":"Light Blue Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_concrete_powder","unlocalizedName":"block.minecraft.light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_dye","unlocalizedName":"item.minecraft.light_blue_dye","localizedName":"Light Blue Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_glazed_terracotta","unlocalizedName":"block.minecraft.light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_shulker_box","unlocalizedName":"block.minecraft.light_blue_shulker_box","localizedName":"Light Blue Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:light_blue_stained_glass","unlocalizedName":"block.minecraft.light_blue_stained_glass","localizedName":"Light Blue Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_stained_glass_pane","unlocalizedName":"block.minecraft.light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_terracotta","unlocalizedName":"block.minecraft.light_blue_terracotta","localizedName":"Light Blue Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_blue_wool","unlocalizedName":"block.minecraft.light_blue_wool","localizedName":"Light Blue Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_banner","unlocalizedName":"block.minecraft.light_gray_banner","localizedName":"Light Gray Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:light_gray_bed","unlocalizedName":"block.minecraft.light_gray_bed","localizedName":"Light Gray Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:light_gray_carpet","unlocalizedName":"block.minecraft.light_gray_carpet","localizedName":"Light Gray Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_concrete","unlocalizedName":"block.minecraft.light_gray_concrete","localizedName":"Light Gray Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_concrete_powder","unlocalizedName":"block.minecraft.light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_dye","unlocalizedName":"item.minecraft.light_gray_dye","localizedName":"Light Gray Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_glazed_terracotta","unlocalizedName":"block.minecraft.light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_shulker_box","unlocalizedName":"block.minecraft.light_gray_shulker_box","localizedName":"Light Gray Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:light_gray_stained_glass","unlocalizedName":"block.minecraft.light_gray_stained_glass","localizedName":"Light Gray Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_stained_glass_pane","unlocalizedName":"block.minecraft.light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_terracotta","unlocalizedName":"block.minecraft.light_gray_terracotta","localizedName":"Light Gray Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_gray_wool","unlocalizedName":"block.minecraft.light_gray_wool","localizedName":"Light Gray Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:light_weighted_pressure_plate","unlocalizedName":"block.minecraft.light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lilac","unlocalizedName":"block.minecraft.lilac","localizedName":"Lilac","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lily_of_the_valley","unlocalizedName":"block.minecraft.lily_of_the_valley","localizedName":"Lily of the Valley","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lily_pad","unlocalizedName":"block.minecraft.lily_pad","localizedName":"Lily Pad","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_banner","unlocalizedName":"block.minecraft.lime_banner","localizedName":"Lime Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:lime_bed","unlocalizedName":"block.minecraft.lime_bed","localizedName":"Lime Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:lime_carpet","unlocalizedName":"block.minecraft.lime_carpet","localizedName":"Lime Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_concrete","unlocalizedName":"block.minecraft.lime_concrete","localizedName":"Lime Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_concrete_powder","unlocalizedName":"block.minecraft.lime_concrete_powder","localizedName":"Lime Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_dye","unlocalizedName":"item.minecraft.lime_dye","localizedName":"Lime Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_glazed_terracotta","unlocalizedName":"block.minecraft.lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_shulker_box","unlocalizedName":"block.minecraft.lime_shulker_box","localizedName":"Lime Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:lime_stained_glass","unlocalizedName":"block.minecraft.lime_stained_glass","localizedName":"Lime Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_stained_glass_pane","unlocalizedName":"block.minecraft.lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_terracotta","unlocalizedName":"block.minecraft.lime_terracotta","localizedName":"Lime Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lime_wool","unlocalizedName":"block.minecraft.lime_wool","localizedName":"Lime Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:lingering_potion","unlocalizedName":"item.minecraft.lingering_potion.effect.water","localizedName":"Lingering Water Bottle","maxDamage":0,"maxStackSize":1},{"id":"minecraft:llama_spawn_egg","unlocalizedName":"item.minecraft.llama_spawn_egg","localizedName":"Llama Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:loom","unlocalizedName":"block.minecraft.loom","localizedName":"Loom","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_banner","unlocalizedName":"block.minecraft.magenta_banner","localizedName":"Magenta Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:magenta_bed","unlocalizedName":"block.minecraft.magenta_bed","localizedName":"Magenta Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:magenta_carpet","unlocalizedName":"block.minecraft.magenta_carpet","localizedName":"Magenta Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_concrete","unlocalizedName":"block.minecraft.magenta_concrete","localizedName":"Magenta Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_concrete_powder","unlocalizedName":"block.minecraft.magenta_concrete_powder","localizedName":"Magenta Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_dye","unlocalizedName":"item.minecraft.magenta_dye","localizedName":"Magenta Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_glazed_terracotta","unlocalizedName":"block.minecraft.magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_shulker_box","unlocalizedName":"block.minecraft.magenta_shulker_box","localizedName":"Magenta Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:magenta_stained_glass","unlocalizedName":"block.minecraft.magenta_stained_glass","localizedName":"Magenta Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_stained_glass_pane","unlocalizedName":"block.minecraft.magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_terracotta","unlocalizedName":"block.minecraft.magenta_terracotta","localizedName":"Magenta Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magenta_wool","unlocalizedName":"block.minecraft.magenta_wool","localizedName":"Magenta Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magma_block","unlocalizedName":"block.minecraft.magma_block","localizedName":"Magma Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magma_cream","unlocalizedName":"item.minecraft.magma_cream","localizedName":"Magma Cream","maxDamage":0,"maxStackSize":64},{"id":"minecraft:magma_cube_spawn_egg","unlocalizedName":"item.minecraft.magma_cube_spawn_egg","localizedName":"Magma Cube Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:map","unlocalizedName":"item.minecraft.map","localizedName":"Empty Map","maxDamage":0,"maxStackSize":64},{"id":"minecraft:melon","unlocalizedName":"block.minecraft.melon","localizedName":"Melon","maxDamage":0,"maxStackSize":64},{"id":"minecraft:melon_seeds","unlocalizedName":"item.minecraft.melon_seeds","localizedName":"Melon Seeds","maxDamage":0,"maxStackSize":64},{"id":"minecraft:melon_slice","unlocalizedName":"item.minecraft.melon_slice","localizedName":"Melon Slice","maxDamage":0,"maxStackSize":64},{"id":"minecraft:milk_bucket","unlocalizedName":"item.minecraft.milk_bucket","localizedName":"Milk Bucket","maxDamage":0,"maxStackSize":1},{"id":"minecraft:minecart","unlocalizedName":"item.minecraft.minecart","localizedName":"Minecart","maxDamage":0,"maxStackSize":1},{"id":"minecraft:mojang_banner_pattern","unlocalizedName":"item.minecraft.mojang_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1},{"id":"minecraft:mooshroom_spawn_egg","unlocalizedName":"item.minecraft.mooshroom_spawn_egg","localizedName":"Mooshroom Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mossy_cobblestone","unlocalizedName":"block.minecraft.mossy_cobblestone","localizedName":"Mossy Cobblestone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mossy_cobblestone_slab","unlocalizedName":"block.minecraft.mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mossy_cobblestone_stairs","unlocalizedName":"block.minecraft.mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mossy_cobblestone_wall","unlocalizedName":"block.minecraft.mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mossy_stone_brick_slab","unlocalizedName":"block.minecraft.mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mossy_stone_brick_stairs","unlocalizedName":"block.minecraft.mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mossy_stone_brick_wall","unlocalizedName":"block.minecraft.mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mossy_stone_bricks","unlocalizedName":"block.minecraft.mossy_stone_bricks","localizedName":"Mossy Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mule_spawn_egg","unlocalizedName":"item.minecraft.mule_spawn_egg","localizedName":"Mule Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mushroom_stem","unlocalizedName":"block.minecraft.mushroom_stem","localizedName":"Mushroom Stem","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mushroom_stew","unlocalizedName":"item.minecraft.mushroom_stew","localizedName":"Mushroom Stew","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_11","unlocalizedName":"item.minecraft.music_disc_11","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_13","unlocalizedName":"item.minecraft.music_disc_13","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_blocks","unlocalizedName":"item.minecraft.music_disc_blocks","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_cat","unlocalizedName":"item.minecraft.music_disc_cat","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_chirp","unlocalizedName":"item.minecraft.music_disc_chirp","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_far","unlocalizedName":"item.minecraft.music_disc_far","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_mall","unlocalizedName":"item.minecraft.music_disc_mall","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_mellohi","unlocalizedName":"item.minecraft.music_disc_mellohi","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_stal","unlocalizedName":"item.minecraft.music_disc_stal","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_strad","unlocalizedName":"item.minecraft.music_disc_strad","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_wait","unlocalizedName":"item.minecraft.music_disc_wait","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:music_disc_ward","unlocalizedName":"item.minecraft.music_disc_ward","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1},{"id":"minecraft:mutton","unlocalizedName":"item.minecraft.mutton","localizedName":"Raw Mutton","maxDamage":0,"maxStackSize":64},{"id":"minecraft:mycelium","unlocalizedName":"block.minecraft.mycelium","localizedName":"Mycelium","maxDamage":0,"maxStackSize":64},{"id":"minecraft:name_tag","unlocalizedName":"item.minecraft.name_tag","localizedName":"Name Tag","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nautilus_shell","unlocalizedName":"item.minecraft.nautilus_shell","localizedName":"Nautilus Shell","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_brick","unlocalizedName":"item.minecraft.nether_brick","localizedName":"Nether Brick","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_brick_fence","unlocalizedName":"block.minecraft.nether_brick_fence","localizedName":"Nether Brick Fence","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_brick_slab","unlocalizedName":"block.minecraft.nether_brick_slab","localizedName":"Nether Brick Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_brick_stairs","unlocalizedName":"block.minecraft.nether_brick_stairs","localizedName":"Nether Brick Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_brick_wall","unlocalizedName":"block.minecraft.nether_brick_wall","localizedName":"Nether Brick Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_bricks","unlocalizedName":"block.minecraft.nether_bricks","localizedName":"Nether Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_quartz_ore","unlocalizedName":"block.minecraft.nether_quartz_ore","localizedName":"Nether Quartz Ore","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_star","unlocalizedName":"item.minecraft.nether_star","localizedName":"Nether Star","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_wart","unlocalizedName":"item.minecraft.nether_wart","localizedName":"Nether Wart","maxDamage":0,"maxStackSize":64},{"id":"minecraft:nether_wart_block","unlocalizedName":"block.minecraft.nether_wart_block","localizedName":"Nether Wart Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:netherrack","unlocalizedName":"block.minecraft.netherrack","localizedName":"Netherrack","maxDamage":0,"maxStackSize":64},{"id":"minecraft:note_block","unlocalizedName":"block.minecraft.note_block","localizedName":"Note Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_boat","unlocalizedName":"item.minecraft.oak_boat","localizedName":"Oak Boat","maxDamage":0,"maxStackSize":1},{"id":"minecraft:oak_button","unlocalizedName":"block.minecraft.oak_button","localizedName":"Oak Button","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_door","unlocalizedName":"block.minecraft.oak_door","localizedName":"Oak Door","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_fence","unlocalizedName":"block.minecraft.oak_fence","localizedName":"Oak Fence","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_fence_gate","unlocalizedName":"block.minecraft.oak_fence_gate","localizedName":"Oak Fence Gate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_leaves","unlocalizedName":"block.minecraft.oak_leaves","localizedName":"Oak Leaves","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_log","unlocalizedName":"block.minecraft.oak_log","localizedName":"Oak Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_planks","unlocalizedName":"block.minecraft.oak_planks","localizedName":"Oak Planks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_pressure_plate","unlocalizedName":"block.minecraft.oak_pressure_plate","localizedName":"Oak Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_sapling","unlocalizedName":"block.minecraft.oak_sapling","localizedName":"Oak Sapling","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_sign","unlocalizedName":"block.minecraft.oak_sign","localizedName":"Oak Sign","maxDamage":0,"maxStackSize":16},{"id":"minecraft:oak_slab","unlocalizedName":"block.minecraft.oak_slab","localizedName":"Oak Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_stairs","unlocalizedName":"block.minecraft.oak_stairs","localizedName":"Oak Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_trapdoor","unlocalizedName":"block.minecraft.oak_trapdoor","localizedName":"Oak Trapdoor","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oak_wood","unlocalizedName":"block.minecraft.oak_wood","localizedName":"Oak Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:observer","unlocalizedName":"block.minecraft.observer","localizedName":"Observer","maxDamage":0,"maxStackSize":64},{"id":"minecraft:obsidian","unlocalizedName":"block.minecraft.obsidian","localizedName":"Obsidian","maxDamage":0,"maxStackSize":64},{"id":"minecraft:ocelot_spawn_egg","unlocalizedName":"item.minecraft.ocelot_spawn_egg","localizedName":"Ocelot Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_banner","unlocalizedName":"block.minecraft.orange_banner","localizedName":"Orange Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:orange_bed","unlocalizedName":"block.minecraft.orange_bed","localizedName":"Orange Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:orange_carpet","unlocalizedName":"block.minecraft.orange_carpet","localizedName":"Orange Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_concrete","unlocalizedName":"block.minecraft.orange_concrete","localizedName":"Orange Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_concrete_powder","unlocalizedName":"block.minecraft.orange_concrete_powder","localizedName":"Orange Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_dye","unlocalizedName":"item.minecraft.orange_dye","localizedName":"Orange Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_glazed_terracotta","unlocalizedName":"block.minecraft.orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_shulker_box","unlocalizedName":"block.minecraft.orange_shulker_box","localizedName":"Orange Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:orange_stained_glass","unlocalizedName":"block.minecraft.orange_stained_glass","localizedName":"Orange Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_stained_glass_pane","unlocalizedName":"block.minecraft.orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_terracotta","unlocalizedName":"block.minecraft.orange_terracotta","localizedName":"Orange Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_tulip","unlocalizedName":"block.minecraft.orange_tulip","localizedName":"Orange Tulip","maxDamage":0,"maxStackSize":64},{"id":"minecraft:orange_wool","unlocalizedName":"block.minecraft.orange_wool","localizedName":"Orange Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:oxeye_daisy","unlocalizedName":"block.minecraft.oxeye_daisy","localizedName":"Oxeye Daisy","maxDamage":0,"maxStackSize":64},{"id":"minecraft:packed_ice","unlocalizedName":"block.minecraft.packed_ice","localizedName":"Packed Ice","maxDamage":0,"maxStackSize":64},{"id":"minecraft:painting","unlocalizedName":"item.minecraft.painting","localizedName":"Painting","maxDamage":0,"maxStackSize":64},{"id":"minecraft:panda_spawn_egg","unlocalizedName":"item.minecraft.panda_spawn_egg","localizedName":"Panda Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:paper","unlocalizedName":"item.minecraft.paper","localizedName":"Paper","maxDamage":0,"maxStackSize":64},{"id":"minecraft:parrot_spawn_egg","unlocalizedName":"item.minecraft.parrot_spawn_egg","localizedName":"Parrot Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:peony","unlocalizedName":"block.minecraft.peony","localizedName":"Peony","maxDamage":0,"maxStackSize":64},{"id":"minecraft:petrified_oak_slab","unlocalizedName":"block.minecraft.petrified_oak_slab","localizedName":"Petrified Oak Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:phantom_membrane","unlocalizedName":"item.minecraft.phantom_membrane","localizedName":"Phantom Membrane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:phantom_spawn_egg","unlocalizedName":"item.minecraft.phantom_spawn_egg","localizedName":"Phantom Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pig_spawn_egg","unlocalizedName":"item.minecraft.pig_spawn_egg","localizedName":"Pig Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pillager_spawn_egg","unlocalizedName":"item.minecraft.pillager_spawn_egg","localizedName":"Pillager Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_banner","unlocalizedName":"block.minecraft.pink_banner","localizedName":"Pink Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:pink_bed","unlocalizedName":"block.minecraft.pink_bed","localizedName":"Pink Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:pink_carpet","unlocalizedName":"block.minecraft.pink_carpet","localizedName":"Pink Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_concrete","unlocalizedName":"block.minecraft.pink_concrete","localizedName":"Pink Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_concrete_powder","unlocalizedName":"block.minecraft.pink_concrete_powder","localizedName":"Pink Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_dye","unlocalizedName":"item.minecraft.pink_dye","localizedName":"Pink Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_glazed_terracotta","unlocalizedName":"block.minecraft.pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_shulker_box","unlocalizedName":"block.minecraft.pink_shulker_box","localizedName":"Pink Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:pink_stained_glass","unlocalizedName":"block.minecraft.pink_stained_glass","localizedName":"Pink Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_stained_glass_pane","unlocalizedName":"block.minecraft.pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_terracotta","unlocalizedName":"block.minecraft.pink_terracotta","localizedName":"Pink Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_tulip","unlocalizedName":"block.minecraft.pink_tulip","localizedName":"Pink Tulip","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pink_wool","unlocalizedName":"block.minecraft.pink_wool","localizedName":"Pink Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:piston","unlocalizedName":"block.minecraft.piston","localizedName":"Piston","maxDamage":0,"maxStackSize":64},{"id":"minecraft:player_head","unlocalizedName":"block.minecraft.player_head","localizedName":"Player Head","maxDamage":0,"maxStackSize":64},{"id":"minecraft:podzol","unlocalizedName":"block.minecraft.podzol","localizedName":"Podzol","maxDamage":0,"maxStackSize":64},{"id":"minecraft:poisonous_potato","unlocalizedName":"item.minecraft.poisonous_potato","localizedName":"Poisonous Potato","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polar_bear_spawn_egg","unlocalizedName":"item.minecraft.polar_bear_spawn_egg","localizedName":"Polar Bear Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_andesite","unlocalizedName":"block.minecraft.polished_andesite","localizedName":"Polished Andesite","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_andesite_slab","unlocalizedName":"block.minecraft.polished_andesite_slab","localizedName":"Polished Andesite Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_andesite_stairs","unlocalizedName":"block.minecraft.polished_andesite_stairs","localizedName":"Polished Andesite Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_diorite","unlocalizedName":"block.minecraft.polished_diorite","localizedName":"Polished Diorite","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_diorite_slab","unlocalizedName":"block.minecraft.polished_diorite_slab","localizedName":"Polished Diorite Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_diorite_stairs","unlocalizedName":"block.minecraft.polished_diorite_stairs","localizedName":"Polished Diorite Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_granite","unlocalizedName":"block.minecraft.polished_granite","localizedName":"Polished Granite","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_granite_slab","unlocalizedName":"block.minecraft.polished_granite_slab","localizedName":"Polished Granite Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:polished_granite_stairs","unlocalizedName":"block.minecraft.polished_granite_stairs","localizedName":"Polished Granite Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:popped_chorus_fruit","unlocalizedName":"item.minecraft.popped_chorus_fruit","localizedName":"Popped Chorus Fruit","maxDamage":0,"maxStackSize":64},{"id":"minecraft:poppy","unlocalizedName":"block.minecraft.poppy","localizedName":"Poppy","maxDamage":0,"maxStackSize":64},{"id":"minecraft:porkchop","unlocalizedName":"item.minecraft.porkchop","localizedName":"Raw Porkchop","maxDamage":0,"maxStackSize":64},{"id":"minecraft:potato","unlocalizedName":"item.minecraft.potato","localizedName":"Potato","maxDamage":0,"maxStackSize":64},{"id":"minecraft:potion","unlocalizedName":"item.minecraft.potion.effect.water","localizedName":"Water Bottle","maxDamage":0,"maxStackSize":1},{"id":"minecraft:powered_rail","unlocalizedName":"block.minecraft.powered_rail","localizedName":"Powered Rail","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine","unlocalizedName":"block.minecraft.prismarine","localizedName":"Prismarine","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine_brick_slab","unlocalizedName":"block.minecraft.prismarine_brick_slab","localizedName":"Prismarine Brick Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine_brick_stairs","unlocalizedName":"block.minecraft.prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine_bricks","unlocalizedName":"block.minecraft.prismarine_bricks","localizedName":"Prismarine Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine_crystals","unlocalizedName":"item.minecraft.prismarine_crystals","localizedName":"Prismarine Crystals","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine_shard","unlocalizedName":"item.minecraft.prismarine_shard","localizedName":"Prismarine Shard","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine_slab","unlocalizedName":"block.minecraft.prismarine_slab","localizedName":"Prismarine Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine_stairs","unlocalizedName":"block.minecraft.prismarine_stairs","localizedName":"Prismarine Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:prismarine_wall","unlocalizedName":"block.minecraft.prismarine_wall","localizedName":"Prismarine Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pufferfish","unlocalizedName":"item.minecraft.pufferfish","localizedName":"Pufferfish","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pufferfish_bucket","unlocalizedName":"item.minecraft.pufferfish_bucket","localizedName":"Bucket of Pufferfish","maxDamage":0,"maxStackSize":1},{"id":"minecraft:pufferfish_spawn_egg","unlocalizedName":"item.minecraft.pufferfish_spawn_egg","localizedName":"Pufferfish Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pumpkin","unlocalizedName":"block.minecraft.pumpkin","localizedName":"Pumpkin","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pumpkin_pie","unlocalizedName":"item.minecraft.pumpkin_pie","localizedName":"Pumpkin Pie","maxDamage":0,"maxStackSize":64},{"id":"minecraft:pumpkin_seeds","unlocalizedName":"item.minecraft.pumpkin_seeds","localizedName":"Pumpkin Seeds","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_banner","unlocalizedName":"block.minecraft.purple_banner","localizedName":"Purple Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:purple_bed","unlocalizedName":"block.minecraft.purple_bed","localizedName":"Purple Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:purple_carpet","unlocalizedName":"block.minecraft.purple_carpet","localizedName":"Purple Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_concrete","unlocalizedName":"block.minecraft.purple_concrete","localizedName":"Purple Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_concrete_powder","unlocalizedName":"block.minecraft.purple_concrete_powder","localizedName":"Purple Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_dye","unlocalizedName":"item.minecraft.purple_dye","localizedName":"Purple Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_glazed_terracotta","unlocalizedName":"block.minecraft.purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_shulker_box","unlocalizedName":"block.minecraft.purple_shulker_box","localizedName":"Purple Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:purple_stained_glass","unlocalizedName":"block.minecraft.purple_stained_glass","localizedName":"Purple Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_stained_glass_pane","unlocalizedName":"block.minecraft.purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_terracotta","unlocalizedName":"block.minecraft.purple_terracotta","localizedName":"Purple Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purple_wool","unlocalizedName":"block.minecraft.purple_wool","localizedName":"Purple Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purpur_block","unlocalizedName":"block.minecraft.purpur_block","localizedName":"Purpur Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purpur_pillar","unlocalizedName":"block.minecraft.purpur_pillar","localizedName":"Purpur Pillar","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purpur_slab","unlocalizedName":"block.minecraft.purpur_slab","localizedName":"Purpur Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:purpur_stairs","unlocalizedName":"block.minecraft.purpur_stairs","localizedName":"Purpur Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:quartz","unlocalizedName":"item.minecraft.quartz","localizedName":"Nether Quartz","maxDamage":0,"maxStackSize":64},{"id":"minecraft:quartz_block","unlocalizedName":"block.minecraft.quartz_block","localizedName":"Block of Quartz","maxDamage":0,"maxStackSize":64},{"id":"minecraft:quartz_pillar","unlocalizedName":"block.minecraft.quartz_pillar","localizedName":"Quartz Pillar","maxDamage":0,"maxStackSize":64},{"id":"minecraft:quartz_slab","unlocalizedName":"block.minecraft.quartz_slab","localizedName":"Quartz Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:quartz_stairs","unlocalizedName":"block.minecraft.quartz_stairs","localizedName":"Quartz Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:rabbit","unlocalizedName":"item.minecraft.rabbit","localizedName":"Raw Rabbit","maxDamage":0,"maxStackSize":64},{"id":"minecraft:rabbit_foot","unlocalizedName":"item.minecraft.rabbit_foot","localizedName":"Rabbit's Foot","maxDamage":0,"maxStackSize":64},{"id":"minecraft:rabbit_hide","unlocalizedName":"item.minecraft.rabbit_hide","localizedName":"Rabbit Hide","maxDamage":0,"maxStackSize":64},{"id":"minecraft:rabbit_spawn_egg","unlocalizedName":"item.minecraft.rabbit_spawn_egg","localizedName":"Rabbit Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:rabbit_stew","unlocalizedName":"item.minecraft.rabbit_stew","localizedName":"Rabbit Stew","maxDamage":0,"maxStackSize":1},{"id":"minecraft:rail","unlocalizedName":"block.minecraft.rail","localizedName":"Rail","maxDamage":0,"maxStackSize":64},{"id":"minecraft:ravager_spawn_egg","unlocalizedName":"item.minecraft.ravager_spawn_egg","localizedName":"Ravager Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_banner","unlocalizedName":"block.minecraft.red_banner","localizedName":"Red Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:red_bed","unlocalizedName":"block.minecraft.red_bed","localizedName":"Red Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:red_carpet","unlocalizedName":"block.minecraft.red_carpet","localizedName":"Red Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_concrete","unlocalizedName":"block.minecraft.red_concrete","localizedName":"Red Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_concrete_powder","unlocalizedName":"block.minecraft.red_concrete_powder","localizedName":"Red Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_dye","unlocalizedName":"item.minecraft.red_dye","localizedName":"Red Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_glazed_terracotta","unlocalizedName":"block.minecraft.red_glazed_terracotta","localizedName":"Red Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_mushroom","unlocalizedName":"block.minecraft.red_mushroom","localizedName":"Red Mushroom","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_mushroom_block","unlocalizedName":"block.minecraft.red_mushroom_block","localizedName":"Red Mushroom Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_nether_brick_slab","unlocalizedName":"block.minecraft.red_nether_brick_slab","localizedName":"Red Nether Brick Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_nether_brick_stairs","unlocalizedName":"block.minecraft.red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_nether_brick_wall","unlocalizedName":"block.minecraft.red_nether_brick_wall","localizedName":"Red Nether Brick Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_nether_bricks","unlocalizedName":"block.minecraft.red_nether_bricks","localizedName":"Red Nether Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_sand","unlocalizedName":"block.minecraft.red_sand","localizedName":"Red Sand","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_sandstone","unlocalizedName":"block.minecraft.red_sandstone","localizedName":"Red Sandstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_sandstone_slab","unlocalizedName":"block.minecraft.red_sandstone_slab","localizedName":"Red Sandstone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_sandstone_stairs","unlocalizedName":"block.minecraft.red_sandstone_stairs","localizedName":"Red Sandstone Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_sandstone_wall","unlocalizedName":"block.minecraft.red_sandstone_wall","localizedName":"Red Sandstone Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_shulker_box","unlocalizedName":"block.minecraft.red_shulker_box","localizedName":"Red Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:red_stained_glass","unlocalizedName":"block.minecraft.red_stained_glass","localizedName":"Red Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_stained_glass_pane","unlocalizedName":"block.minecraft.red_stained_glass_pane","localizedName":"Red Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_terracotta","unlocalizedName":"block.minecraft.red_terracotta","localizedName":"Red Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_tulip","unlocalizedName":"block.minecraft.red_tulip","localizedName":"Red Tulip","maxDamage":0,"maxStackSize":64},{"id":"minecraft:red_wool","unlocalizedName":"block.minecraft.red_wool","localizedName":"Red Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:redstone","unlocalizedName":"item.minecraft.redstone","localizedName":"Redstone Dust","maxDamage":0,"maxStackSize":64},{"id":"minecraft:redstone_block","unlocalizedName":"block.minecraft.redstone_block","localizedName":"Block of Redstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:redstone_lamp","unlocalizedName":"block.minecraft.redstone_lamp","localizedName":"Redstone Lamp","maxDamage":0,"maxStackSize":64},{"id":"minecraft:redstone_ore","unlocalizedName":"block.minecraft.redstone_ore","localizedName":"Redstone Ore","maxDamage":0,"maxStackSize":64},{"id":"minecraft:redstone_torch","unlocalizedName":"block.minecraft.redstone_torch","localizedName":"Redstone Torch","maxDamage":0,"maxStackSize":64},{"id":"minecraft:repeater","unlocalizedName":"block.minecraft.repeater","localizedName":"Redstone Repeater","maxDamage":0,"maxStackSize":64},{"id":"minecraft:repeating_command_block","unlocalizedName":"block.minecraft.repeating_command_block","localizedName":"Repeating Command Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:rose_bush","unlocalizedName":"block.minecraft.rose_bush","localizedName":"Rose Bush","maxDamage":0,"maxStackSize":64},{"id":"minecraft:rotten_flesh","unlocalizedName":"item.minecraft.rotten_flesh","localizedName":"Rotten Flesh","maxDamage":0,"maxStackSize":64},{"id":"minecraft:saddle","unlocalizedName":"item.minecraft.saddle","localizedName":"Saddle","maxDamage":0,"maxStackSize":1},{"id":"minecraft:salmon","unlocalizedName":"item.minecraft.salmon","localizedName":"Raw Salmon","maxDamage":0,"maxStackSize":64},{"id":"minecraft:salmon_bucket","unlocalizedName":"item.minecraft.salmon_bucket","localizedName":"Bucket of Salmon","maxDamage":0,"maxStackSize":1},{"id":"minecraft:salmon_spawn_egg","unlocalizedName":"item.minecraft.salmon_spawn_egg","localizedName":"Salmon Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sand","unlocalizedName":"block.minecraft.sand","localizedName":"Sand","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sandstone","unlocalizedName":"block.minecraft.sandstone","localizedName":"Sandstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sandstone_slab","unlocalizedName":"block.minecraft.sandstone_slab","localizedName":"Sandstone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sandstone_stairs","unlocalizedName":"block.minecraft.sandstone_stairs","localizedName":"Sandstone Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sandstone_wall","unlocalizedName":"block.minecraft.sandstone_wall","localizedName":"Sandstone Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:scaffolding","unlocalizedName":"block.minecraft.scaffolding","localizedName":"Scaffolding","maxDamage":0,"maxStackSize":64},{"id":"minecraft:scute","unlocalizedName":"item.minecraft.scute","localizedName":"Scute","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sea_lantern","unlocalizedName":"block.minecraft.sea_lantern","localizedName":"Sea Lantern","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sea_pickle","unlocalizedName":"block.minecraft.sea_pickle","localizedName":"Sea Pickle","maxDamage":0,"maxStackSize":64},{"id":"minecraft:seagrass","unlocalizedName":"block.minecraft.seagrass","localizedName":"Seagrass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:shears","unlocalizedName":"item.minecraft.shears","localizedName":"Shears","maxDamage":238,"maxStackSize":1},{"id":"minecraft:sheep_spawn_egg","unlocalizedName":"item.minecraft.sheep_spawn_egg","localizedName":"Sheep Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:shield","unlocalizedName":"item.minecraft.shield","localizedName":"Shield","maxDamage":336,"maxStackSize":1},{"id":"minecraft:shulker_box","unlocalizedName":"block.minecraft.shulker_box","localizedName":"Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:shulker_shell","unlocalizedName":"item.minecraft.shulker_shell","localizedName":"Shulker Shell","maxDamage":0,"maxStackSize":64},{"id":"minecraft:shulker_spawn_egg","unlocalizedName":"item.minecraft.shulker_spawn_egg","localizedName":"Shulker Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:silverfish_spawn_egg","unlocalizedName":"item.minecraft.silverfish_spawn_egg","localizedName":"Silverfish Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:skeleton_horse_spawn_egg","unlocalizedName":"item.minecraft.skeleton_horse_spawn_egg","localizedName":"Skeleton Horse Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:skeleton_skull","unlocalizedName":"block.minecraft.skeleton_skull","localizedName":"Skeleton Skull","maxDamage":0,"maxStackSize":64},{"id":"minecraft:skeleton_spawn_egg","unlocalizedName":"item.minecraft.skeleton_spawn_egg","localizedName":"Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:skull_banner_pattern","unlocalizedName":"item.minecraft.skull_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1},{"id":"minecraft:slime_ball","unlocalizedName":"item.minecraft.slime_ball","localizedName":"Slimeball","maxDamage":0,"maxStackSize":64},{"id":"minecraft:slime_block","unlocalizedName":"block.minecraft.slime_block","localizedName":"Slime Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:slime_spawn_egg","unlocalizedName":"item.minecraft.slime_spawn_egg","localizedName":"Slime Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smithing_table","unlocalizedName":"block.minecraft.smithing_table","localizedName":"Smithing Table","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smoker","unlocalizedName":"block.minecraft.smoker","localizedName":"Smoker","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_quartz","unlocalizedName":"block.minecraft.smooth_quartz","localizedName":"Smooth Quartz","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_quartz_slab","unlocalizedName":"block.minecraft.smooth_quartz_slab","localizedName":"Smooth Quartz Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_quartz_stairs","unlocalizedName":"block.minecraft.smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_red_sandstone","unlocalizedName":"block.minecraft.smooth_red_sandstone","localizedName":"Smooth Red Sandstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_red_sandstone_slab","unlocalizedName":"block.minecraft.smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_red_sandstone_stairs","unlocalizedName":"block.minecraft.smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_sandstone","unlocalizedName":"block.minecraft.smooth_sandstone","localizedName":"Smooth Sandstone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_sandstone_slab","unlocalizedName":"block.minecraft.smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_sandstone_stairs","unlocalizedName":"block.minecraft.smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_stone","unlocalizedName":"block.minecraft.smooth_stone","localizedName":"Smooth Stone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:smooth_stone_slab","unlocalizedName":"block.minecraft.smooth_stone_slab","localizedName":"Smooth Stone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:snow","unlocalizedName":"block.minecraft.snow","localizedName":"Snow","maxDamage":0,"maxStackSize":64},{"id":"minecraft:snow_block","unlocalizedName":"block.minecraft.snow_block","localizedName":"Snow Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:snowball","unlocalizedName":"item.minecraft.snowball","localizedName":"Snowball","maxDamage":0,"maxStackSize":16},{"id":"minecraft:soul_sand","unlocalizedName":"block.minecraft.soul_sand","localizedName":"Soul Sand","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spawner","unlocalizedName":"block.minecraft.spawner","localizedName":"Spawner","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spectral_arrow","unlocalizedName":"item.minecraft.spectral_arrow","localizedName":"Spectral Arrow","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spider_eye","unlocalizedName":"item.minecraft.spider_eye","localizedName":"Spider Eye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spider_spawn_egg","unlocalizedName":"item.minecraft.spider_spawn_egg","localizedName":"Spider Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:splash_potion","unlocalizedName":"item.minecraft.splash_potion.effect.water","localizedName":"Splash Water Bottle","maxDamage":0,"maxStackSize":1},{"id":"minecraft:sponge","unlocalizedName":"block.minecraft.sponge","localizedName":"Sponge","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_boat","unlocalizedName":"item.minecraft.spruce_boat","localizedName":"Spruce Boat","maxDamage":0,"maxStackSize":1},{"id":"minecraft:spruce_button","unlocalizedName":"block.minecraft.spruce_button","localizedName":"Spruce Button","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_door","unlocalizedName":"block.minecraft.spruce_door","localizedName":"Spruce Door","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_fence","unlocalizedName":"block.minecraft.spruce_fence","localizedName":"Spruce Fence","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_fence_gate","unlocalizedName":"block.minecraft.spruce_fence_gate","localizedName":"Spruce Fence Gate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_leaves","unlocalizedName":"block.minecraft.spruce_leaves","localizedName":"Spruce Leaves","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_log","unlocalizedName":"block.minecraft.spruce_log","localizedName":"Spruce Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_planks","unlocalizedName":"block.minecraft.spruce_planks","localizedName":"Spruce Planks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_pressure_plate","unlocalizedName":"block.minecraft.spruce_pressure_plate","localizedName":"Spruce Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_sapling","unlocalizedName":"block.minecraft.spruce_sapling","localizedName":"Spruce Sapling","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_sign","unlocalizedName":"block.minecraft.spruce_sign","localizedName":"Spruce Sign","maxDamage":0,"maxStackSize":16},{"id":"minecraft:spruce_slab","unlocalizedName":"block.minecraft.spruce_slab","localizedName":"Spruce Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_stairs","unlocalizedName":"block.minecraft.spruce_stairs","localizedName":"Spruce Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_trapdoor","unlocalizedName":"block.minecraft.spruce_trapdoor","localizedName":"Spruce Trapdoor","maxDamage":0,"maxStackSize":64},{"id":"minecraft:spruce_wood","unlocalizedName":"block.minecraft.spruce_wood","localizedName":"Spruce Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:squid_spawn_egg","unlocalizedName":"item.minecraft.squid_spawn_egg","localizedName":"Squid Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stick","unlocalizedName":"item.minecraft.stick","localizedName":"Stick","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sticky_piston","unlocalizedName":"block.minecraft.sticky_piston","localizedName":"Sticky Piston","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone","unlocalizedName":"block.minecraft.stone","localizedName":"Stone","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_axe","unlocalizedName":"item.minecraft.stone_axe","localizedName":"Stone Axe","maxDamage":131,"maxStackSize":1},{"id":"minecraft:stone_brick_slab","unlocalizedName":"block.minecraft.stone_brick_slab","localizedName":"Stone Brick Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_brick_stairs","unlocalizedName":"block.minecraft.stone_brick_stairs","localizedName":"Stone Brick Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_brick_wall","unlocalizedName":"block.minecraft.stone_brick_wall","localizedName":"Stone Brick Wall","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_bricks","unlocalizedName":"block.minecraft.stone_bricks","localizedName":"Stone Bricks","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_button","unlocalizedName":"block.minecraft.stone_button","localizedName":"Stone Button","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_hoe","unlocalizedName":"item.minecraft.stone_hoe","localizedName":"Stone Hoe","maxDamage":131,"maxStackSize":1},{"id":"minecraft:stone_pickaxe","unlocalizedName":"item.minecraft.stone_pickaxe","localizedName":"Stone Pickaxe","maxDamage":131,"maxStackSize":1},{"id":"minecraft:stone_pressure_plate","unlocalizedName":"block.minecraft.stone_pressure_plate","localizedName":"Stone Pressure Plate","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_shovel","unlocalizedName":"item.minecraft.stone_shovel","localizedName":"Stone Shovel","maxDamage":131,"maxStackSize":1},{"id":"minecraft:stone_slab","unlocalizedName":"block.minecraft.stone_slab","localizedName":"Stone Slab","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_stairs","unlocalizedName":"block.minecraft.stone_stairs","localizedName":"Stone Stairs","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stone_sword","unlocalizedName":"item.minecraft.stone_sword","localizedName":"Stone Sword","maxDamage":131,"maxStackSize":1},{"id":"minecraft:stonecutter","unlocalizedName":"block.minecraft.stonecutter","localizedName":"Stonecutter","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stray_spawn_egg","unlocalizedName":"item.minecraft.stray_spawn_egg","localizedName":"Stray Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:string","unlocalizedName":"item.minecraft.string","localizedName":"String","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_acacia_log","unlocalizedName":"block.minecraft.stripped_acacia_log","localizedName":"Stripped Acacia Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_acacia_wood","unlocalizedName":"block.minecraft.stripped_acacia_wood","localizedName":"Stripped Acacia Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_birch_log","unlocalizedName":"block.minecraft.stripped_birch_log","localizedName":"Stripped Birch Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_birch_wood","unlocalizedName":"block.minecraft.stripped_birch_wood","localizedName":"Stripped Birch Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_dark_oak_log","unlocalizedName":"block.minecraft.stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_dark_oak_wood","unlocalizedName":"block.minecraft.stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_jungle_log","unlocalizedName":"block.minecraft.stripped_jungle_log","localizedName":"Stripped Jungle Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_jungle_wood","unlocalizedName":"block.minecraft.stripped_jungle_wood","localizedName":"Stripped Jungle Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_oak_log","unlocalizedName":"block.minecraft.stripped_oak_log","localizedName":"Stripped Oak Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_oak_wood","unlocalizedName":"block.minecraft.stripped_oak_wood","localizedName":"Stripped Oak Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_spruce_log","unlocalizedName":"block.minecraft.stripped_spruce_log","localizedName":"Stripped Spruce Log","maxDamage":0,"maxStackSize":64},{"id":"minecraft:stripped_spruce_wood","unlocalizedName":"block.minecraft.stripped_spruce_wood","localizedName":"Stripped Spruce Wood","maxDamage":0,"maxStackSize":64},{"id":"minecraft:structure_block","unlocalizedName":"block.minecraft.structure_block","localizedName":"Structure Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:structure_void","unlocalizedName":"block.minecraft.structure_void","localizedName":"Structure Void","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sugar","unlocalizedName":"item.minecraft.sugar","localizedName":"Sugar","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sugar_cane","unlocalizedName":"block.minecraft.sugar_cane","localizedName":"Sugar Cane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:sunflower","unlocalizedName":"block.minecraft.sunflower","localizedName":"Sunflower","maxDamage":0,"maxStackSize":64},{"id":"minecraft:suspicious_stew","unlocalizedName":"item.minecraft.suspicious_stew","localizedName":"Suspicious Stew","maxDamage":0,"maxStackSize":1},{"id":"minecraft:sweet_berries","unlocalizedName":"item.minecraft.sweet_berries","localizedName":"Sweet Berries","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tall_grass","unlocalizedName":"block.minecraft.tall_grass","localizedName":"Tall Grass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:terracotta","unlocalizedName":"block.minecraft.terracotta","localizedName":"Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tipped_arrow","unlocalizedName":"item.minecraft.tipped_arrow.effect.poison","localizedName":"Arrow of Poison","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tnt","unlocalizedName":"block.minecraft.tnt","localizedName":"TNT","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tnt_minecart","unlocalizedName":"item.minecraft.tnt_minecart","localizedName":"Minecart with TNT","maxDamage":0,"maxStackSize":1},{"id":"minecraft:torch","unlocalizedName":"block.minecraft.torch","localizedName":"Torch","maxDamage":0,"maxStackSize":64},{"id":"minecraft:totem_of_undying","unlocalizedName":"item.minecraft.totem_of_undying","localizedName":"Totem of Undying","maxDamage":0,"maxStackSize":1},{"id":"minecraft:trader_llama_spawn_egg","unlocalizedName":"item.minecraft.trader_llama_spawn_egg","localizedName":"Trader Llama Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:trapped_chest","unlocalizedName":"block.minecraft.trapped_chest","localizedName":"Trapped Chest","maxDamage":0,"maxStackSize":64},{"id":"minecraft:trident","unlocalizedName":"item.minecraft.trident","localizedName":"Trident","maxDamage":250,"maxStackSize":1},{"id":"minecraft:tripwire_hook","unlocalizedName":"block.minecraft.tripwire_hook","localizedName":"Tripwire Hook","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tropical_fish","unlocalizedName":"item.minecraft.tropical_fish","localizedName":"Tropical Fish","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tropical_fish_bucket","unlocalizedName":"item.minecraft.tropical_fish_bucket","localizedName":"Bucket of Tropical Fish","maxDamage":0,"maxStackSize":1},{"id":"minecraft:tropical_fish_spawn_egg","unlocalizedName":"item.minecraft.tropical_fish_spawn_egg","localizedName":"Tropical Fish Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tube_coral","unlocalizedName":"block.minecraft.tube_coral","localizedName":"Tube Coral","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tube_coral_block","unlocalizedName":"block.minecraft.tube_coral_block","localizedName":"Tube Coral Block","maxDamage":0,"maxStackSize":64},{"id":"minecraft:tube_coral_fan","unlocalizedName":"block.minecraft.tube_coral_fan","localizedName":"Tube Coral Fan","maxDamage":0,"maxStackSize":64},{"id":"minecraft:turtle_egg","unlocalizedName":"block.minecraft.turtle_egg","localizedName":"Turtle Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:turtle_helmet","unlocalizedName":"item.minecraft.turtle_helmet","localizedName":"Turtle Shell","maxDamage":275,"maxStackSize":1},{"id":"minecraft:turtle_spawn_egg","unlocalizedName":"item.minecraft.turtle_spawn_egg","localizedName":"Turtle Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:vex_spawn_egg","unlocalizedName":"item.minecraft.vex_spawn_egg","localizedName":"Vex Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:villager_spawn_egg","unlocalizedName":"item.minecraft.villager_spawn_egg","localizedName":"Villager Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:vindicator_spawn_egg","unlocalizedName":"item.minecraft.vindicator_spawn_egg","localizedName":"Vindicator Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:vine","unlocalizedName":"block.minecraft.vine","localizedName":"Vines","maxDamage":0,"maxStackSize":64},{"id":"minecraft:wandering_trader_spawn_egg","unlocalizedName":"item.minecraft.wandering_trader_spawn_egg","localizedName":"Wandering Trader Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:water_bucket","unlocalizedName":"item.minecraft.water_bucket","localizedName":"Water Bucket","maxDamage":0,"maxStackSize":1},{"id":"minecraft:wet_sponge","unlocalizedName":"block.minecraft.wet_sponge","localizedName":"Wet Sponge","maxDamage":0,"maxStackSize":64},{"id":"minecraft:wheat","unlocalizedName":"item.minecraft.wheat","localizedName":"Wheat","maxDamage":0,"maxStackSize":64},{"id":"minecraft:wheat_seeds","unlocalizedName":"item.minecraft.wheat_seeds","localizedName":"Wheat Seeds","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_banner","unlocalizedName":"block.minecraft.white_banner","localizedName":"White Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:white_bed","unlocalizedName":"block.minecraft.white_bed","localizedName":"White Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:white_carpet","unlocalizedName":"block.minecraft.white_carpet","localizedName":"White Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_concrete","unlocalizedName":"block.minecraft.white_concrete","localizedName":"White Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_concrete_powder","unlocalizedName":"block.minecraft.white_concrete_powder","localizedName":"White Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_dye","unlocalizedName":"item.minecraft.white_dye","localizedName":"White Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_glazed_terracotta","unlocalizedName":"block.minecraft.white_glazed_terracotta","localizedName":"White Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_shulker_box","unlocalizedName":"block.minecraft.white_shulker_box","localizedName":"White Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:white_stained_glass","unlocalizedName":"block.minecraft.white_stained_glass","localizedName":"White Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_stained_glass_pane","unlocalizedName":"block.minecraft.white_stained_glass_pane","localizedName":"White Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_terracotta","unlocalizedName":"block.minecraft.white_terracotta","localizedName":"White Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_tulip","unlocalizedName":"block.minecraft.white_tulip","localizedName":"White Tulip","maxDamage":0,"maxStackSize":64},{"id":"minecraft:white_wool","unlocalizedName":"block.minecraft.white_wool","localizedName":"White Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:witch_spawn_egg","unlocalizedName":"item.minecraft.witch_spawn_egg","localizedName":"Witch Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:wither_rose","unlocalizedName":"block.minecraft.wither_rose","localizedName":"Wither Rose","maxDamage":0,"maxStackSize":64},{"id":"minecraft:wither_skeleton_skull","unlocalizedName":"block.minecraft.wither_skeleton_skull","localizedName":"Wither Skeleton Skull","maxDamage":0,"maxStackSize":64},{"id":"minecraft:wither_skeleton_spawn_egg","unlocalizedName":"item.minecraft.wither_skeleton_spawn_egg","localizedName":"Wither Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:wolf_spawn_egg","unlocalizedName":"item.minecraft.wolf_spawn_egg","localizedName":"Wolf Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:wooden_axe","unlocalizedName":"item.minecraft.wooden_axe","localizedName":"Wooden Axe","maxDamage":59,"maxStackSize":1},{"id":"minecraft:wooden_hoe","unlocalizedName":"item.minecraft.wooden_hoe","localizedName":"Wooden Hoe","maxDamage":59,"maxStackSize":1},{"id":"minecraft:wooden_pickaxe","unlocalizedName":"item.minecraft.wooden_pickaxe","localizedName":"Wooden Pickaxe","maxDamage":59,"maxStackSize":1},{"id":"minecraft:wooden_shovel","unlocalizedName":"item.minecraft.wooden_shovel","localizedName":"Wooden Shovel","maxDamage":59,"maxStackSize":1},{"id":"minecraft:wooden_sword","unlocalizedName":"item.minecraft.wooden_sword","localizedName":"Wooden Sword","maxDamage":59,"maxStackSize":1},{"id":"minecraft:writable_book","unlocalizedName":"item.minecraft.writable_book","localizedName":"Book and Quill","maxDamage":0,"maxStackSize":1},{"id":"minecraft:written_book","unlocalizedName":"item.minecraft.written_book","localizedName":"Written Book","maxDamage":0,"maxStackSize":16},{"id":"minecraft:yellow_banner","unlocalizedName":"block.minecraft.yellow_banner","localizedName":"Yellow Banner","maxDamage":0,"maxStackSize":16},{"id":"minecraft:yellow_bed","unlocalizedName":"block.minecraft.yellow_bed","localizedName":"Yellow Bed","maxDamage":0,"maxStackSize":1},{"id":"minecraft:yellow_carpet","unlocalizedName":"block.minecraft.yellow_carpet","localizedName":"Yellow Carpet","maxDamage":0,"maxStackSize":64},{"id":"minecraft:yellow_concrete","unlocalizedName":"block.minecraft.yellow_concrete","localizedName":"Yellow Concrete","maxDamage":0,"maxStackSize":64},{"id":"minecraft:yellow_concrete_powder","unlocalizedName":"block.minecraft.yellow_concrete_powder","localizedName":"Yellow Concrete Powder","maxDamage":0,"maxStackSize":64},{"id":"minecraft:yellow_dye","unlocalizedName":"item.minecraft.yellow_dye","localizedName":"Yellow Dye","maxDamage":0,"maxStackSize":64},{"id":"minecraft:yellow_glazed_terracotta","unlocalizedName":"block.minecraft.yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:yellow_shulker_box","unlocalizedName":"block.minecraft.yellow_shulker_box","localizedName":"Yellow Shulker Box","maxDamage":0,"maxStackSize":1},{"id":"minecraft:yellow_stained_glass","unlocalizedName":"block.minecraft.yellow_stained_glass","localizedName":"Yellow Stained Glass","maxDamage":0,"maxStackSize":64},{"id":"minecraft:yellow_stained_glass_pane","unlocalizedName":"block.minecraft.yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","maxDamage":0,"maxStackSize":64},{"id":"minecraft:yellow_terracotta","unlocalizedName":"block.minecraft.yellow_terracotta","localizedName":"Yellow Terracotta","maxDamage":0,"maxStackSize":64},{"id":"minecraft:yellow_wool","unlocalizedName":"block.minecraft.yellow_wool","localizedName":"Yellow Wool","maxDamage":0,"maxStackSize":64},{"id":"minecraft:zombie_head","unlocalizedName":"block.minecraft.zombie_head","localizedName":"Zombie Head","maxDamage":0,"maxStackSize":64},{"id":"minecraft:zombie_horse_spawn_egg","unlocalizedName":"item.minecraft.zombie_horse_spawn_egg","localizedName":"Zombie Horse Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:zombie_pigman_spawn_egg","unlocalizedName":"item.minecraft.zombie_pigman_spawn_egg","localizedName":"Zombie Pigman Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:zombie_spawn_egg","unlocalizedName":"item.minecraft.zombie_spawn_egg","localizedName":"Zombie Spawn Egg","maxDamage":0,"maxStackSize":64},{"id":"minecraft:zombie_villager_spawn_egg","unlocalizedName":"item.minecraft.zombie_villager_spawn_egg","localizedName":"Zombie Villager Spawn Egg","maxDamage":0,"maxStackSize":64}] diff --git a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.116.json b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.116.json deleted file mode 100644 index 543059690..000000000 --- a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.116.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":"minecraft:acacia_boat","localizedName":"Acacia Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.acacia_boat"},{"id":"minecraft:acacia_button","localizedName":"Acacia Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_button"},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_door"},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence"},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence_gate"},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_leaves"},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_log"},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_planks"},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_pressure_plate"},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_sapling"},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.acacia_sign"},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_slab"},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_stairs"},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_trapdoor"},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_wood"},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.activator_rail"},{"id":"minecraft:air","localizedName":"Air","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.air"},{"id":"minecraft:allium","localizedName":"Allium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.allium"},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ancient_debris"},{"id":"minecraft:andesite","localizedName":"Andesite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite"},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_slab"},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_stairs"},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_wall"},{"id":"minecraft:anvil","localizedName":"Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.anvil"},{"id":"minecraft:apple","localizedName":"Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.apple"},{"id":"minecraft:armor_stand","localizedName":"Armor Stand","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.armor_stand"},{"id":"minecraft:arrow","localizedName":"Arrow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.arrow"},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.azure_bluet"},{"id":"minecraft:baked_potato","localizedName":"Baked Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.baked_potato"},{"id":"minecraft:bamboo","localizedName":"Bamboo","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo"},{"id":"minecraft:barrel","localizedName":"Barrel","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.barrel"},{"id":"minecraft:barrier","localizedName":"Barrier","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.barrier"},{"id":"minecraft:basalt","localizedName":"Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.basalt"},{"id":"minecraft:bat_spawn_egg","localizedName":"Bat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bat_spawn_egg"},{"id":"minecraft:beacon","localizedName":"Beacon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.beacon"},{"id":"minecraft:bedrock","localizedName":"Bedrock","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bedrock"},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bee_nest"},{"id":"minecraft:bee_spawn_egg","localizedName":"Bee Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bee_spawn_egg"},{"id":"minecraft:beef","localizedName":"Raw Beef","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beef"},{"id":"minecraft:beehive","localizedName":"Beehive","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.beehive"},{"id":"minecraft:beetroot","localizedName":"Beetroot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot"},{"id":"minecraft:beetroot_seeds","localizedName":"Beetroot Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot_seeds"},{"id":"minecraft:beetroot_soup","localizedName":"Beetroot Soup","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.beetroot_soup"},{"id":"minecraft:bell","localizedName":"Bell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bell"},{"id":"minecraft:birch_boat","localizedName":"Birch Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.birch_boat"},{"id":"minecraft:birch_button","localizedName":"Birch Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_button"},{"id":"minecraft:birch_door","localizedName":"Birch Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_door"},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence"},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence_gate"},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_leaves"},{"id":"minecraft:birch_log","localizedName":"Birch Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_log"},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_planks"},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_pressure_plate"},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_sapling"},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.birch_sign"},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_slab"},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_stairs"},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_trapdoor"},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_wood"},{"id":"minecraft:black_banner","localizedName":"Black Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.black_banner"},{"id":"minecraft:black_bed","localizedName":"Black Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.black_bed"},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_carpet"},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete"},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete_powder"},{"id":"minecraft:black_dye","localizedName":"Black Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.black_dye"},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_glazed_terracotta"},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.black_shulker_box"},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass"},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass_pane"},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_terracotta"},{"id":"minecraft:black_wool","localizedName":"Black Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_wool"},{"id":"minecraft:blackstone","localizedName":"Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone"},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_slab"},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_stairs"},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_wall"},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blast_furnace"},{"id":"minecraft:blaze_powder","localizedName":"Blaze Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_powder"},{"id":"minecraft:blaze_rod","localizedName":"Blaze Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_rod"},{"id":"minecraft:blaze_spawn_egg","localizedName":"Blaze Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_spawn_egg"},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.blue_banner"},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.blue_bed"},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_carpet"},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete"},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete_powder"},{"id":"minecraft:blue_dye","localizedName":"Blue Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blue_dye"},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_glazed_terracotta"},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_ice"},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_orchid"},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.blue_shulker_box"},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass"},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass_pane"},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_terracotta"},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_wool"},{"id":"minecraft:bone","localizedName":"Bone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bone"},{"id":"minecraft:bone_block","localizedName":"Bone Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bone_block"},{"id":"minecraft:bone_meal","localizedName":"Bone Meal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bone_meal"},{"id":"minecraft:book","localizedName":"Book","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.book"},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bookshelf"},{"id":"minecraft:bow","localizedName":"Bow","maxDamage":384,"maxStackSize":1,"unlocalizedName":"item.minecraft.bow"},{"id":"minecraft:bowl","localizedName":"Bowl","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bowl"},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral"},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_block"},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_fan"},{"id":"minecraft:bread","localizedName":"Bread","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bread"},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brewing_stand"},{"id":"minecraft:brick","localizedName":"Brick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.brick"},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_slab"},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_stairs"},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_wall"},{"id":"minecraft:bricks","localizedName":"Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bricks"},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.brown_banner"},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.brown_bed"},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_carpet"},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete"},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete_powder"},{"id":"minecraft:brown_dye","localizedName":"Brown Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.brown_dye"},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_glazed_terracotta"},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom"},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom_block"},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.brown_shulker_box"},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass"},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass_pane"},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_terracotta"},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_wool"},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral"},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_block"},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_fan"},{"id":"minecraft:bucket","localizedName":"Bucket","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.bucket"},{"id":"minecraft:cactus","localizedName":"Cactus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cactus"},{"id":"minecraft:cake","localizedName":"Cake","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cake"},{"id":"minecraft:campfire","localizedName":"Campfire","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.campfire"},{"id":"minecraft:carrot","localizedName":"Carrot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.carrot"},{"id":"minecraft:carrot_on_a_stick","localizedName":"Carrot on a Stick","maxDamage":25,"maxStackSize":1,"unlocalizedName":"item.minecraft.carrot_on_a_stick"},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cartography_table"},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.carved_pumpkin"},{"id":"minecraft:cat_spawn_egg","localizedName":"Cat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cat_spawn_egg"},{"id":"minecraft:cauldron","localizedName":"Cauldron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cauldron"},{"id":"minecraft:cave_spider_spawn_egg","localizedName":"Cave Spider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cave_spider_spawn_egg"},{"id":"minecraft:chain","localizedName":"Chain","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chain"},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chain_command_block"},{"id":"minecraft:chainmail_boots","localizedName":"Chainmail Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_boots"},{"id":"minecraft:chainmail_chestplate","localizedName":"Chainmail Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_chestplate"},{"id":"minecraft:chainmail_helmet","localizedName":"Chainmail Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_helmet"},{"id":"minecraft:chainmail_leggings","localizedName":"Chainmail Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_leggings"},{"id":"minecraft:charcoal","localizedName":"Charcoal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.charcoal"},{"id":"minecraft:chest","localizedName":"Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chest"},{"id":"minecraft:chest_minecart","localizedName":"Minecart with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.chest_minecart"},{"id":"minecraft:chicken","localizedName":"Raw Chicken","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chicken"},{"id":"minecraft:chicken_spawn_egg","localizedName":"Chicken Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chicken_spawn_egg"},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chipped_anvil"},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_nether_bricks"},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_polished_blackstone"},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_quartz_block"},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_red_sandstone"},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_sandstone"},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_stone_bricks"},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_flower"},{"id":"minecraft:chorus_fruit","localizedName":"Chorus Fruit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chorus_fruit"},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_plant"},{"id":"minecraft:clay","localizedName":"Clay","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.clay"},{"id":"minecraft:clay_ball","localizedName":"Clay Ball","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.clay_ball"},{"id":"minecraft:clock","localizedName":"Clock","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.clock"},{"id":"minecraft:coal","localizedName":"Coal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.coal"},{"id":"minecraft:coal_block","localizedName":"Block of Coal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coal_block"},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coal_ore"},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coarse_dirt"},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone"},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_slab"},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_stairs"},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_wall"},{"id":"minecraft:cobweb","localizedName":"Cobweb","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobweb"},{"id":"minecraft:cocoa_beans","localizedName":"Cocoa Beans","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cocoa_beans"},{"id":"minecraft:cod","localizedName":"Raw Cod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cod"},{"id":"minecraft:cod_bucket","localizedName":"Bucket of Cod","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.cod_bucket"},{"id":"minecraft:cod_spawn_egg","localizedName":"Cod Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cod_spawn_egg"},{"id":"minecraft:command_block","localizedName":"Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.command_block"},{"id":"minecraft:command_block_minecart","localizedName":"Minecart with Command Block","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.command_block_minecart"},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.comparator"},{"id":"minecraft:compass","localizedName":"Compass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.compass"},{"id":"minecraft:composter","localizedName":"Composter","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.composter"},{"id":"minecraft:conduit","localizedName":"Conduit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.conduit"},{"id":"minecraft:cooked_beef","localizedName":"Steak","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_beef"},{"id":"minecraft:cooked_chicken","localizedName":"Cooked Chicken","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_chicken"},{"id":"minecraft:cooked_cod","localizedName":"Cooked Cod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_cod"},{"id":"minecraft:cooked_mutton","localizedName":"Cooked Mutton","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_mutton"},{"id":"minecraft:cooked_porkchop","localizedName":"Cooked Porkchop","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_porkchop"},{"id":"minecraft:cooked_rabbit","localizedName":"Cooked Rabbit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_rabbit"},{"id":"minecraft:cooked_salmon","localizedName":"Cooked Salmon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_salmon"},{"id":"minecraft:cookie","localizedName":"Cookie","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cookie"},{"id":"minecraft:cornflower","localizedName":"Cornflower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cornflower"},{"id":"minecraft:cow_spawn_egg","localizedName":"Cow Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cow_spawn_egg"},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_nether_bricks"},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_polished_blackstone_bricks"},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_stone_bricks"},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crafting_table"},{"id":"minecraft:creeper_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.creeper_banner_pattern"},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.creeper_head"},{"id":"minecraft:creeper_spawn_egg","localizedName":"Creeper Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.creeper_spawn_egg"},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_button"},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_door"},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence"},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence_gate"},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fungus"},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_hyphae"},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_nylium"},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_planks"},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_pressure_plate"},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_roots"},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.crimson_sign"},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_slab"},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stairs"},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stem"},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_trapdoor"},{"id":"minecraft:crossbow","localizedName":"Crossbow","maxDamage":326,"maxStackSize":1,"unlocalizedName":"item.minecraft.crossbow"},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crying_obsidian"},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone"},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone_slab"},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone"},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone_slab"},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.cyan_banner"},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_bed"},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_carpet"},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete"},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete_powder"},{"id":"minecraft:cyan_dye","localizedName":"Cyan Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cyan_dye"},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_glazed_terracotta"},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_shulker_box"},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass"},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass_pane"},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_terracotta"},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_wool"},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.damaged_anvil"},{"id":"minecraft:dandelion","localizedName":"Dandelion","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dandelion"},{"id":"minecraft:dark_oak_boat","localizedName":"Dark Oak Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.dark_oak_boat"},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_button"},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_door"},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence"},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence_gate"},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_leaves"},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_log"},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_planks"},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_pressure_plate"},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_sapling"},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.dark_oak_sign"},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_slab"},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_stairs"},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_trapdoor"},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_wood"},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine"},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_slab"},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_stairs"},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.daylight_detector"},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral"},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_block"},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_fan"},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral"},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_block"},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_fan"},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bush"},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral"},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_block"},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_fan"},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral"},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_block"},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_fan"},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral"},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_block"},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_fan"},{"id":"minecraft:debug_stick","localizedName":"Debug Stick","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.debug_stick"},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.detector_rail"},{"id":"minecraft:diamond","localizedName":"Diamond","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.diamond"},{"id":"minecraft:diamond_axe","localizedName":"Diamond Axe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_axe"},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_block"},{"id":"minecraft:diamond_boots","localizedName":"Diamond Boots","maxDamage":429,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_boots"},{"id":"minecraft:diamond_chestplate","localizedName":"Diamond Chestplate","maxDamage":528,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_chestplate"},{"id":"minecraft:diamond_helmet","localizedName":"Diamond Helmet","maxDamage":363,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_helmet"},{"id":"minecraft:diamond_hoe","localizedName":"Diamond Hoe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_hoe"},{"id":"minecraft:diamond_horse_armor","localizedName":"Diamond Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_horse_armor"},{"id":"minecraft:diamond_leggings","localizedName":"Diamond Leggings","maxDamage":495,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_leggings"},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_ore"},{"id":"minecraft:diamond_pickaxe","localizedName":"Diamond Pickaxe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_pickaxe"},{"id":"minecraft:diamond_shovel","localizedName":"Diamond Shovel","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_shovel"},{"id":"minecraft:diamond_sword","localizedName":"Diamond Sword","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_sword"},{"id":"minecraft:diorite","localizedName":"Diorite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite"},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_slab"},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_stairs"},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_wall"},{"id":"minecraft:dirt","localizedName":"Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dirt"},{"id":"minecraft:dispenser","localizedName":"Dispenser","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dispenser"},{"id":"minecraft:dolphin_spawn_egg","localizedName":"Dolphin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dolphin_spawn_egg"},{"id":"minecraft:donkey_spawn_egg","localizedName":"Donkey Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.donkey_spawn_egg"},{"id":"minecraft:dragon_breath","localizedName":"Dragon's Breath","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dragon_breath"},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_egg"},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_head"},{"id":"minecraft:dried_kelp","localizedName":"Dried Kelp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dried_kelp"},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dried_kelp_block"},{"id":"minecraft:dropper","localizedName":"Dropper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dropper"},{"id":"minecraft:drowned_spawn_egg","localizedName":"Drowned Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.drowned_spawn_egg"},{"id":"minecraft:egg","localizedName":"Egg","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.egg"},{"id":"minecraft:elder_guardian_spawn_egg","localizedName":"Elder Guardian Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.elder_guardian_spawn_egg"},{"id":"minecraft:elytra","localizedName":"Elytra","maxDamage":432,"maxStackSize":1,"unlocalizedName":"item.minecraft.elytra"},{"id":"minecraft:emerald","localizedName":"Emerald","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.emerald"},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_block"},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_ore"},{"id":"minecraft:enchanted_book","localizedName":"Enchanted Book","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.enchanted_book"},{"id":"minecraft:enchanted_golden_apple","localizedName":"Enchanted Golden Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.enchanted_golden_apple"},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.enchanting_table"},{"id":"minecraft:end_crystal","localizedName":"End Crystal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.end_crystal"},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_portal_frame"},{"id":"minecraft:end_rod","localizedName":"End Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_rod"},{"id":"minecraft:end_stone","localizedName":"End Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone"},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_slab"},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_stairs"},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_wall"},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_bricks"},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ender_chest"},{"id":"minecraft:ender_eye","localizedName":"Eye of Ender","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ender_eye"},{"id":"minecraft:ender_pearl","localizedName":"Ender Pearl","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.ender_pearl"},{"id":"minecraft:enderman_spawn_egg","localizedName":"Enderman Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.enderman_spawn_egg"},{"id":"minecraft:endermite_spawn_egg","localizedName":"Endermite Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.endermite_spawn_egg"},{"id":"minecraft:evoker_spawn_egg","localizedName":"Evoker Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.evoker_spawn_egg"},{"id":"minecraft:experience_bottle","localizedName":"Bottle o' Enchanting","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.experience_bottle"},{"id":"minecraft:farmland","localizedName":"Farmland","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.farmland"},{"id":"minecraft:feather","localizedName":"Feather","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.feather"},{"id":"minecraft:fermented_spider_eye","localizedName":"Fermented Spider Eye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fermented_spider_eye"},{"id":"minecraft:fern","localizedName":"Fern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fern"},{"id":"minecraft:filled_map","localizedName":"Map","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.filled_map"},{"id":"minecraft:fire_charge","localizedName":"Fire Charge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fire_charge"},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral"},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_block"},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_fan"},{"id":"minecraft:firework_rocket","localizedName":"Firework Rocket","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.firework_rocket"},{"id":"minecraft:firework_star","localizedName":"Firework Star","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.firework_star"},{"id":"minecraft:fishing_rod","localizedName":"Fishing Rod","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.fishing_rod"},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fletching_table"},{"id":"minecraft:flint","localizedName":"Flint","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.flint"},{"id":"minecraft:flint_and_steel","localizedName":"Flint and Steel","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.flint_and_steel"},{"id":"minecraft:flower_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.flower_banner_pattern"},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.flower_pot"},{"id":"minecraft:fox_spawn_egg","localizedName":"Fox Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fox_spawn_egg"},{"id":"minecraft:furnace","localizedName":"Furnace","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.furnace"},{"id":"minecraft:furnace_minecart","localizedName":"Minecart with Furnace","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.furnace_minecart"},{"id":"minecraft:ghast_spawn_egg","localizedName":"Ghast Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_spawn_egg"},{"id":"minecraft:ghast_tear","localizedName":"Ghast Tear","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_tear"},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gilded_blackstone"},{"id":"minecraft:glass","localizedName":"Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glass"},{"id":"minecraft:glass_bottle","localizedName":"Glass Bottle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glass_bottle"},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glass_pane"},{"id":"minecraft:glistering_melon_slice","localizedName":"Glistering Melon Slice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glistering_melon_slice"},{"id":"minecraft:globe_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.globe_banner_pattern"},{"id":"minecraft:glowstone","localizedName":"Glowstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glowstone"},{"id":"minecraft:glowstone_dust","localizedName":"Glowstone Dust","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glowstone_dust"},{"id":"minecraft:gold_block","localizedName":"Block of Gold","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gold_block"},{"id":"minecraft:gold_ingot","localizedName":"Gold Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gold_ingot"},{"id":"minecraft:gold_nugget","localizedName":"Gold Nugget","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gold_nugget"},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gold_ore"},{"id":"minecraft:golden_apple","localizedName":"Golden Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.golden_apple"},{"id":"minecraft:golden_axe","localizedName":"Golden Axe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_axe"},{"id":"minecraft:golden_boots","localizedName":"Golden Boots","maxDamage":91,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_boots"},{"id":"minecraft:golden_carrot","localizedName":"Golden Carrot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.golden_carrot"},{"id":"minecraft:golden_chestplate","localizedName":"Golden Chestplate","maxDamage":112,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_chestplate"},{"id":"minecraft:golden_helmet","localizedName":"Golden Helmet","maxDamage":77,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_helmet"},{"id":"minecraft:golden_hoe","localizedName":"Golden Hoe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_hoe"},{"id":"minecraft:golden_horse_armor","localizedName":"Golden Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_horse_armor"},{"id":"minecraft:golden_leggings","localizedName":"Golden Leggings","maxDamage":105,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_leggings"},{"id":"minecraft:golden_pickaxe","localizedName":"Golden Pickaxe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_pickaxe"},{"id":"minecraft:golden_shovel","localizedName":"Golden Shovel","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_shovel"},{"id":"minecraft:golden_sword","localizedName":"Golden Sword","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_sword"},{"id":"minecraft:granite","localizedName":"Granite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite"},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_slab"},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_stairs"},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_wall"},{"id":"minecraft:grass","localizedName":"Grass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grass"},{"id":"minecraft:grass_block","localizedName":"Grass Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grass_block"},{"id":"minecraft:grass_path","localizedName":"Grass Path","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grass_path"},{"id":"minecraft:gravel","localizedName":"Gravel","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gravel"},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.gray_banner"},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.gray_bed"},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_carpet"},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete"},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete_powder"},{"id":"minecraft:gray_dye","localizedName":"Gray Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gray_dye"},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_glazed_terracotta"},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.gray_shulker_box"},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass"},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass_pane"},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_terracotta"},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_wool"},{"id":"minecraft:green_banner","localizedName":"Green Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.green_banner"},{"id":"minecraft:green_bed","localizedName":"Green Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.green_bed"},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_carpet"},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete"},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete_powder"},{"id":"minecraft:green_dye","localizedName":"Green Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.green_dye"},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_glazed_terracotta"},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.green_shulker_box"},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass"},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass_pane"},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_terracotta"},{"id":"minecraft:green_wool","localizedName":"Green Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_wool"},{"id":"minecraft:grindstone","localizedName":"Grindstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grindstone"},{"id":"minecraft:guardian_spawn_egg","localizedName":"Guardian Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.guardian_spawn_egg"},{"id":"minecraft:gunpowder","localizedName":"Gunpowder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gunpowder"},{"id":"minecraft:hay_block","localizedName":"Hay Bale","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hay_block"},{"id":"minecraft:heart_of_the_sea","localizedName":"Heart of the Sea","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.heart_of_the_sea"},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.heavy_weighted_pressure_plate"},{"id":"minecraft:hoglin_spawn_egg","localizedName":"Hoglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.hoglin_spawn_egg"},{"id":"minecraft:honey_block","localizedName":"Honey Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.honey_block"},{"id":"minecraft:honey_bottle","localizedName":"Honey Bottle","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.honey_bottle"},{"id":"minecraft:honeycomb","localizedName":"Honeycomb","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.honeycomb"},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.honeycomb_block"},{"id":"minecraft:hopper","localizedName":"Hopper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hopper"},{"id":"minecraft:hopper_minecart","localizedName":"Minecart with Hopper","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.hopper_minecart"},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral"},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_block"},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_fan"},{"id":"minecraft:horse_spawn_egg","localizedName":"Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.horse_spawn_egg"},{"id":"minecraft:husk_spawn_egg","localizedName":"Husk Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.husk_spawn_egg"},{"id":"minecraft:ice","localizedName":"Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ice"},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_chiseled_stone_bricks"},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cobblestone"},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cracked_stone_bricks"},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_mossy_stone_bricks"},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone"},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone_bricks"},{"id":"minecraft:ink_sac","localizedName":"Ink Sac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ink_sac"},{"id":"minecraft:iron_axe","localizedName":"Iron Axe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_axe"},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_bars"},{"id":"minecraft:iron_block","localizedName":"Block of Iron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_block"},{"id":"minecraft:iron_boots","localizedName":"Iron Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_boots"},{"id":"minecraft:iron_chestplate","localizedName":"Iron Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_chestplate"},{"id":"minecraft:iron_door","localizedName":"Iron Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_door"},{"id":"minecraft:iron_helmet","localizedName":"Iron Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_helmet"},{"id":"minecraft:iron_hoe","localizedName":"Iron Hoe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_hoe"},{"id":"minecraft:iron_horse_armor","localizedName":"Iron Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_horse_armor"},{"id":"minecraft:iron_ingot","localizedName":"Iron Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.iron_ingot"},{"id":"minecraft:iron_leggings","localizedName":"Iron Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_leggings"},{"id":"minecraft:iron_nugget","localizedName":"Iron Nugget","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.iron_nugget"},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_ore"},{"id":"minecraft:iron_pickaxe","localizedName":"Iron Pickaxe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_pickaxe"},{"id":"minecraft:iron_shovel","localizedName":"Iron Shovel","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_shovel"},{"id":"minecraft:iron_sword","localizedName":"Iron Sword","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_sword"},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_trapdoor"},{"id":"minecraft:item_frame","localizedName":"Item Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.item_frame"},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o'Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jack_o_lantern"},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jigsaw"},{"id":"minecraft:jukebox","localizedName":"Jukebox","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jukebox"},{"id":"minecraft:jungle_boat","localizedName":"Jungle Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.jungle_boat"},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_button"},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_door"},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence"},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence_gate"},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_leaves"},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_log"},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_planks"},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_pressure_plate"},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_sapling"},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.jungle_sign"},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_slab"},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_stairs"},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_trapdoor"},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_wood"},{"id":"minecraft:kelp","localizedName":"Kelp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.kelp"},{"id":"minecraft:knowledge_book","localizedName":"Knowledge Book","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.knowledge_book"},{"id":"minecraft:ladder","localizedName":"Ladder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ladder"},{"id":"minecraft:lantern","localizedName":"Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lantern"},{"id":"minecraft:lapis_block","localizedName":"Lapis Lazuli Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_block"},{"id":"minecraft:lapis_lazuli","localizedName":"Lapis Lazuli","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lapis_lazuli"},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_ore"},{"id":"minecraft:large_fern","localizedName":"Large Fern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.large_fern"},{"id":"minecraft:lava_bucket","localizedName":"Lava Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.lava_bucket"},{"id":"minecraft:lead","localizedName":"Lead","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lead"},{"id":"minecraft:leather","localizedName":"Leather","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.leather"},{"id":"minecraft:leather_boots","localizedName":"Leather Boots","maxDamage":65,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_boots"},{"id":"minecraft:leather_chestplate","localizedName":"Leather Tunic","maxDamage":80,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_chestplate"},{"id":"minecraft:leather_helmet","localizedName":"Leather Cap","maxDamage":55,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_helmet"},{"id":"minecraft:leather_horse_armor","localizedName":"Leather Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_horse_armor"},{"id":"minecraft:leather_leggings","localizedName":"Leather Pants","maxDamage":75,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_leggings"},{"id":"minecraft:lectern","localizedName":"Lectern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lectern"},{"id":"minecraft:lever","localizedName":"Lever","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lever"},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.light_blue_banner"},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_bed"},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_carpet"},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete"},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete_powder"},{"id":"minecraft:light_blue_dye","localizedName":"Light Blue Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.light_blue_dye"},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_glazed_terracotta"},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_shulker_box"},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass"},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass_pane"},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_terracotta"},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_wool"},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.light_gray_banner"},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_bed"},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_carpet"},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete"},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete_powder"},{"id":"minecraft:light_gray_dye","localizedName":"Light Gray Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.light_gray_dye"},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_glazed_terracotta"},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_shulker_box"},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass"},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass_pane"},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_terracotta"},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_wool"},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_weighted_pressure_plate"},{"id":"minecraft:lilac","localizedName":"Lilac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lilac"},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lily_of_the_valley"},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lily_pad"},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.lime_banner"},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.lime_bed"},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_carpet"},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete"},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete_powder"},{"id":"minecraft:lime_dye","localizedName":"Lime Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lime_dye"},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_glazed_terracotta"},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.lime_shulker_box"},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass"},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass_pane"},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_terracotta"},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_wool"},{"id":"minecraft:lingering_potion","localizedName":"Lingering Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.lingering_potion.effect.water"},{"id":"minecraft:llama_spawn_egg","localizedName":"Llama Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.llama_spawn_egg"},{"id":"minecraft:lodestone","localizedName":"Lodestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lodestone"},{"id":"minecraft:loom","localizedName":"Loom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.loom"},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.magenta_banner"},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_bed"},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_carpet"},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete"},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete_powder"},{"id":"minecraft:magenta_dye","localizedName":"Magenta Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magenta_dye"},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_glazed_terracotta"},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_shulker_box"},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass"},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass_pane"},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_terracotta"},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_wool"},{"id":"minecraft:magma_block","localizedName":"Magma Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magma_block"},{"id":"minecraft:magma_cream","localizedName":"Magma Cream","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cream"},{"id":"minecraft:magma_cube_spawn_egg","localizedName":"Magma Cube Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cube_spawn_egg"},{"id":"minecraft:map","localizedName":"Empty Map","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.map"},{"id":"minecraft:melon","localizedName":"Melon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.melon"},{"id":"minecraft:melon_seeds","localizedName":"Melon Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.melon_seeds"},{"id":"minecraft:melon_slice","localizedName":"Melon Slice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.melon_slice"},{"id":"minecraft:milk_bucket","localizedName":"Milk Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.milk_bucket"},{"id":"minecraft:minecart","localizedName":"Minecart","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.minecart"},{"id":"minecraft:mojang_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mojang_banner_pattern"},{"id":"minecraft:mooshroom_spawn_egg","localizedName":"Mooshroom Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mooshroom_spawn_egg"},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone"},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_slab"},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_stairs"},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_wall"},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_slab"},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_stairs"},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_wall"},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_bricks"},{"id":"minecraft:mule_spawn_egg","localizedName":"Mule Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mule_spawn_egg"},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mushroom_stem"},{"id":"minecraft:mushroom_stew","localizedName":"Mushroom Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mushroom_stew"},{"id":"minecraft:music_disc_11","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_11"},{"id":"minecraft:music_disc_13","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_13"},{"id":"minecraft:music_disc_blocks","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_blocks"},{"id":"minecraft:music_disc_cat","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_cat"},{"id":"minecraft:music_disc_chirp","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_chirp"},{"id":"minecraft:music_disc_far","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_far"},{"id":"minecraft:music_disc_mall","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mall"},{"id":"minecraft:music_disc_mellohi","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mellohi"},{"id":"minecraft:music_disc_pigstep","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_pigstep"},{"id":"minecraft:music_disc_stal","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_stal"},{"id":"minecraft:music_disc_strad","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_strad"},{"id":"minecraft:music_disc_wait","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_wait"},{"id":"minecraft:music_disc_ward","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_ward"},{"id":"minecraft:mutton","localizedName":"Raw Mutton","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mutton"},{"id":"minecraft:mycelium","localizedName":"Mycelium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mycelium"},{"id":"minecraft:name_tag","localizedName":"Name Tag","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.name_tag"},{"id":"minecraft:nautilus_shell","localizedName":"Nautilus Shell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nautilus_shell"},{"id":"minecraft:nether_brick","localizedName":"Nether Brick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_brick"},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_fence"},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_slab"},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_stairs"},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_wall"},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_bricks"},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_gold_ore"},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_quartz_ore"},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_sprouts"},{"id":"minecraft:nether_star","localizedName":"Nether Star","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_star"},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_wart"},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_wart_block"},{"id":"minecraft:netherite_axe","localizedName":"Netherite Axe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_axe"},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.netherite_block"},{"id":"minecraft:netherite_boots","localizedName":"Netherite Boots","maxDamage":481,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_boots"},{"id":"minecraft:netherite_chestplate","localizedName":"Netherite Chestplate","maxDamage":592,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_chestplate"},{"id":"minecraft:netherite_helmet","localizedName":"Netherite Helmet","maxDamage":407,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_helmet"},{"id":"minecraft:netherite_hoe","localizedName":"Netherite Hoe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_hoe"},{"id":"minecraft:netherite_ingot","localizedName":"Netherite Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_ingot"},{"id":"minecraft:netherite_leggings","localizedName":"Netherite Leggings","maxDamage":555,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_leggings"},{"id":"minecraft:netherite_pickaxe","localizedName":"Netherite Pickaxe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_pickaxe"},{"id":"minecraft:netherite_scrap","localizedName":"Netherite Scrap","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_scrap"},{"id":"minecraft:netherite_shovel","localizedName":"Netherite Shovel","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_shovel"},{"id":"minecraft:netherite_sword","localizedName":"Netherite Sword","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_sword"},{"id":"minecraft:netherrack","localizedName":"Netherrack","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.netherrack"},{"id":"minecraft:note_block","localizedName":"Note Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.note_block"},{"id":"minecraft:oak_boat","localizedName":"Oak Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.oak_boat"},{"id":"minecraft:oak_button","localizedName":"Oak Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_button"},{"id":"minecraft:oak_door","localizedName":"Oak Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_door"},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence"},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence_gate"},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_leaves"},{"id":"minecraft:oak_log","localizedName":"Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_log"},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_planks"},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_pressure_plate"},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_sapling"},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.oak_sign"},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_slab"},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_stairs"},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_trapdoor"},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_wood"},{"id":"minecraft:observer","localizedName":"Observer","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.observer"},{"id":"minecraft:obsidian","localizedName":"Obsidian","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.obsidian"},{"id":"minecraft:ocelot_spawn_egg","localizedName":"Ocelot Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ocelot_spawn_egg"},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.orange_banner"},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.orange_bed"},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_carpet"},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete"},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete_powder"},{"id":"minecraft:orange_dye","localizedName":"Orange Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.orange_dye"},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_glazed_terracotta"},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.orange_shulker_box"},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass"},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass_pane"},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_terracotta"},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_tulip"},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_wool"},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxeye_daisy"},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.packed_ice"},{"id":"minecraft:painting","localizedName":"Painting","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.painting"},{"id":"minecraft:panda_spawn_egg","localizedName":"Panda Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.panda_spawn_egg"},{"id":"minecraft:paper","localizedName":"Paper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.paper"},{"id":"minecraft:parrot_spawn_egg","localizedName":"Parrot Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.parrot_spawn_egg"},{"id":"minecraft:peony","localizedName":"Peony","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.peony"},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.petrified_oak_slab"},{"id":"minecraft:phantom_membrane","localizedName":"Phantom Membrane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_membrane"},{"id":"minecraft:phantom_spawn_egg","localizedName":"Phantom Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_spawn_egg"},{"id":"minecraft:pig_spawn_egg","localizedName":"Pig Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pig_spawn_egg"},{"id":"minecraft:piglin_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.piglin_banner_pattern"},{"id":"minecraft:piglin_brute_spawn_egg","localizedName":"Piglin Brute Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_brute_spawn_egg"},{"id":"minecraft:piglin_spawn_egg","localizedName":"Piglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_spawn_egg"},{"id":"minecraft:pillager_spawn_egg","localizedName":"Pillager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pillager_spawn_egg"},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.pink_banner"},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.pink_bed"},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_carpet"},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete"},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete_powder"},{"id":"minecraft:pink_dye","localizedName":"Pink Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pink_dye"},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_glazed_terracotta"},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.pink_shulker_box"},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass"},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass_pane"},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_terracotta"},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_tulip"},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_wool"},{"id":"minecraft:piston","localizedName":"Piston","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.piston"},{"id":"minecraft:player_head","localizedName":"Player Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.player_head"},{"id":"minecraft:podzol","localizedName":"Podzol","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.podzol"},{"id":"minecraft:poisonous_potato","localizedName":"Poisonous Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.poisonous_potato"},{"id":"minecraft:polar_bear_spawn_egg","localizedName":"Polar Bear Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.polar_bear_spawn_egg"},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite"},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_slab"},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_stairs"},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_basalt"},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone"},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_slab"},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_stairs"},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_wall"},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_bricks"},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_button"},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_pressure_plate"},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_slab"},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_stairs"},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_wall"},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite"},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_slab"},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_stairs"},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite"},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_slab"},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_stairs"},{"id":"minecraft:popped_chorus_fruit","localizedName":"Popped Chorus Fruit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.popped_chorus_fruit"},{"id":"minecraft:poppy","localizedName":"Poppy","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.poppy"},{"id":"minecraft:porkchop","localizedName":"Raw Porkchop","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.porkchop"},{"id":"minecraft:potato","localizedName":"Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.potato"},{"id":"minecraft:potion","localizedName":"Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.potion.effect.water"},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.powered_rail"},{"id":"minecraft:prismarine","localizedName":"Prismarine","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine"},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_slab"},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_stairs"},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_bricks"},{"id":"minecraft:prismarine_crystals","localizedName":"Prismarine Crystals","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_crystals"},{"id":"minecraft:prismarine_shard","localizedName":"Prismarine Shard","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_shard"},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_slab"},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_stairs"},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_wall"},{"id":"minecraft:pufferfish","localizedName":"Pufferfish","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish"},{"id":"minecraft:pufferfish_bucket","localizedName":"Bucket of Pufferfish","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.pufferfish_bucket"},{"id":"minecraft:pufferfish_spawn_egg","localizedName":"Pufferfish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish_spawn_egg"},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pumpkin"},{"id":"minecraft:pumpkin_pie","localizedName":"Pumpkin Pie","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_pie"},{"id":"minecraft:pumpkin_seeds","localizedName":"Pumpkin Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_seeds"},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.purple_banner"},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.purple_bed"},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_carpet"},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete"},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete_powder"},{"id":"minecraft:purple_dye","localizedName":"Purple Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.purple_dye"},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_glazed_terracotta"},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.purple_shulker_box"},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass"},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass_pane"},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_terracotta"},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_wool"},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_block"},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_pillar"},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_slab"},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_stairs"},{"id":"minecraft:quartz","localizedName":"Nether Quartz","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.quartz"},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_block"},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_bricks"},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_pillar"},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_slab"},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_stairs"},{"id":"minecraft:rabbit","localizedName":"Raw Rabbit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit"},{"id":"minecraft:rabbit_foot","localizedName":"Rabbit's Foot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_foot"},{"id":"minecraft:rabbit_hide","localizedName":"Rabbit Hide","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_hide"},{"id":"minecraft:rabbit_spawn_egg","localizedName":"Rabbit Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_spawn_egg"},{"id":"minecraft:rabbit_stew","localizedName":"Rabbit Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.rabbit_stew"},{"id":"minecraft:rail","localizedName":"Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rail"},{"id":"minecraft:ravager_spawn_egg","localizedName":"Ravager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ravager_spawn_egg"},{"id":"minecraft:red_banner","localizedName":"Red Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.red_banner"},{"id":"minecraft:red_bed","localizedName":"Red Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.red_bed"},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_carpet"},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete"},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete_powder"},{"id":"minecraft:red_dye","localizedName":"Red Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.red_dye"},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_glazed_terracotta"},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom"},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom_block"},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_slab"},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_stairs"},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_wall"},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_bricks"},{"id":"minecraft:red_sand","localizedName":"Red Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sand"},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone"},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_slab"},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_stairs"},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_wall"},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.red_shulker_box"},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass"},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass_pane"},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_terracotta"},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_tulip"},{"id":"minecraft:red_wool","localizedName":"Red Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_wool"},{"id":"minecraft:redstone","localizedName":"Redstone Dust","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.redstone"},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_block"},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_lamp"},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_ore"},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_torch"},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.repeater"},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.repeating_command_block"},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.respawn_anchor"},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rose_bush"},{"id":"minecraft:rotten_flesh","localizedName":"Rotten Flesh","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rotten_flesh"},{"id":"minecraft:saddle","localizedName":"Saddle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.saddle"},{"id":"minecraft:salmon","localizedName":"Raw Salmon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.salmon"},{"id":"minecraft:salmon_bucket","localizedName":"Bucket of Salmon","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.salmon_bucket"},{"id":"minecraft:salmon_spawn_egg","localizedName":"Salmon Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.salmon_spawn_egg"},{"id":"minecraft:sand","localizedName":"Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sand"},{"id":"minecraft:sandstone","localizedName":"Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone"},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_slab"},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_stairs"},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_wall"},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.scaffolding"},{"id":"minecraft:scute","localizedName":"Scute","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.scute"},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sea_lantern"},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sea_pickle"},{"id":"minecraft:seagrass","localizedName":"Seagrass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.seagrass"},{"id":"minecraft:shears","localizedName":"Shears","maxDamage":238,"maxStackSize":1,"unlocalizedName":"item.minecraft.shears"},{"id":"minecraft:sheep_spawn_egg","localizedName":"Sheep Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sheep_spawn_egg"},{"id":"minecraft:shield","localizedName":"Shield","maxDamage":336,"maxStackSize":1,"unlocalizedName":"item.minecraft.shield"},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.shroomlight"},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.shulker_box"},{"id":"minecraft:shulker_shell","localizedName":"Shulker Shell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_shell"},{"id":"minecraft:shulker_spawn_egg","localizedName":"Shulker Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_spawn_egg"},{"id":"minecraft:silverfish_spawn_egg","localizedName":"Silverfish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.silverfish_spawn_egg"},{"id":"minecraft:skeleton_horse_spawn_egg","localizedName":"Skeleton Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_horse_spawn_egg"},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.skeleton_skull"},{"id":"minecraft:skeleton_spawn_egg","localizedName":"Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_spawn_egg"},{"id":"minecraft:skull_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.skull_banner_pattern"},{"id":"minecraft:slime_ball","localizedName":"Slimeball","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.slime_ball"},{"id":"minecraft:slime_block","localizedName":"Slime Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.slime_block"},{"id":"minecraft:slime_spawn_egg","localizedName":"Slime Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.slime_spawn_egg"},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smithing_table"},{"id":"minecraft:smoker","localizedName":"Smoker","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smoker"},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz"},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_slab"},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_stairs"},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone"},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_slab"},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_stairs"},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone"},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_slab"},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_stairs"},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone"},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone_slab"},{"id":"minecraft:snow","localizedName":"Snow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.snow"},{"id":"minecraft:snow_block","localizedName":"Snow Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.snow_block"},{"id":"minecraft:snowball","localizedName":"Snowball","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.snowball"},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_campfire"},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_lantern"},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_sand"},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_soil"},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_torch"},{"id":"minecraft:spawner","localizedName":"Spawner","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spawner"},{"id":"minecraft:spectral_arrow","localizedName":"Spectral Arrow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spectral_arrow"},{"id":"minecraft:spider_eye","localizedName":"Spider Eye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spider_eye"},{"id":"minecraft:spider_spawn_egg","localizedName":"Spider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spider_spawn_egg"},{"id":"minecraft:splash_potion","localizedName":"Splash Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.splash_potion.effect.water"},{"id":"minecraft:sponge","localizedName":"Sponge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sponge"},{"id":"minecraft:spruce_boat","localizedName":"Spruce Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.spruce_boat"},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_button"},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_door"},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence"},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence_gate"},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_leaves"},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_log"},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_planks"},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_pressure_plate"},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_sapling"},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.spruce_sign"},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_slab"},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_stairs"},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_trapdoor"},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_wood"},{"id":"minecraft:squid_spawn_egg","localizedName":"Squid Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.squid_spawn_egg"},{"id":"minecraft:stick","localizedName":"Stick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.stick"},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sticky_piston"},{"id":"minecraft:stone","localizedName":"Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone"},{"id":"minecraft:stone_axe","localizedName":"Stone Axe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_axe"},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_slab"},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_stairs"},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_wall"},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_bricks"},{"id":"minecraft:stone_button","localizedName":"Stone Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_button"},{"id":"minecraft:stone_hoe","localizedName":"Stone Hoe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_hoe"},{"id":"minecraft:stone_pickaxe","localizedName":"Stone Pickaxe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_pickaxe"},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_pressure_plate"},{"id":"minecraft:stone_shovel","localizedName":"Stone Shovel","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_shovel"},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_slab"},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_stairs"},{"id":"minecraft:stone_sword","localizedName":"Stone Sword","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_sword"},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stonecutter"},{"id":"minecraft:stray_spawn_egg","localizedName":"Stray Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.stray_spawn_egg"},{"id":"minecraft:strider_spawn_egg","localizedName":"Strider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.strider_spawn_egg"},{"id":"minecraft:string","localizedName":"String","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.string"},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_log"},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_wood"},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_log"},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_wood"},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_hyphae"},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_stem"},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_log"},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_wood"},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_log"},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_wood"},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_log"},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_wood"},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_log"},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_wood"},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_hyphae"},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_stem"},{"id":"minecraft:structure_block","localizedName":"Structure Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.structure_block"},{"id":"minecraft:structure_void","localizedName":"Structure Void","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.structure_void"},{"id":"minecraft:sugar","localizedName":"Sugar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sugar"},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sugar_cane"},{"id":"minecraft:sunflower","localizedName":"Sunflower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sunflower"},{"id":"minecraft:suspicious_stew","localizedName":"Suspicious Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.suspicious_stew"},{"id":"minecraft:sweet_berries","localizedName":"Sweet Berries","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sweet_berries"},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tall_grass"},{"id":"minecraft:target","localizedName":"Target","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.target"},{"id":"minecraft:terracotta","localizedName":"Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.terracotta"},{"id":"minecraft:tipped_arrow","localizedName":"Arrow of Poison","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tipped_arrow.effect.poison"},{"id":"minecraft:tnt","localizedName":"TNT","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tnt"},{"id":"minecraft:tnt_minecart","localizedName":"Minecart with TNT","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.tnt_minecart"},{"id":"minecraft:torch","localizedName":"Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.torch"},{"id":"minecraft:totem_of_undying","localizedName":"Totem of Undying","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.totem_of_undying"},{"id":"minecraft:trader_llama_spawn_egg","localizedName":"Trader Llama Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.trader_llama_spawn_egg"},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.trapped_chest"},{"id":"minecraft:trident","localizedName":"Trident","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.trident"},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tripwire_hook"},{"id":"minecraft:tropical_fish","localizedName":"Tropical Fish","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish"},{"id":"minecraft:tropical_fish_bucket","localizedName":"Bucket of Tropical Fish","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.tropical_fish_bucket"},{"id":"minecraft:tropical_fish_spawn_egg","localizedName":"Tropical Fish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish_spawn_egg"},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral"},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_block"},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_fan"},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.turtle_egg"},{"id":"minecraft:turtle_helmet","localizedName":"Turtle Shell","maxDamage":275,"maxStackSize":1,"unlocalizedName":"item.minecraft.turtle_helmet"},{"id":"minecraft:turtle_spawn_egg","localizedName":"Turtle Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.turtle_spawn_egg"},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.twisting_vines"},{"id":"minecraft:vex_spawn_egg","localizedName":"Vex Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.vex_spawn_egg"},{"id":"minecraft:villager_spawn_egg","localizedName":"Villager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.villager_spawn_egg"},{"id":"minecraft:vindicator_spawn_egg","localizedName":"Vindicator Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.vindicator_spawn_egg"},{"id":"minecraft:vine","localizedName":"Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.vine"},{"id":"minecraft:wandering_trader_spawn_egg","localizedName":"Wandering Trader Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wandering_trader_spawn_egg"},{"id":"minecraft:warped_button","localizedName":"Warped Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_button"},{"id":"minecraft:warped_door","localizedName":"Warped Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_door"},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence"},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence_gate"},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fungus"},{"id":"minecraft:warped_fungus_on_a_stick","localizedName":"Warped Fungus on a Stick","maxDamage":100,"maxStackSize":1,"unlocalizedName":"item.minecraft.warped_fungus_on_a_stick"},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_hyphae"},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_nylium"},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_planks"},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_pressure_plate"},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_roots"},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.warped_sign"},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_slab"},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stairs"},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stem"},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_trapdoor"},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_wart_block"},{"id":"minecraft:water_bucket","localizedName":"Water Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.water_bucket"},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weeping_vines"},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wet_sponge"},{"id":"minecraft:wheat","localizedName":"Wheat","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wheat"},{"id":"minecraft:wheat_seeds","localizedName":"Wheat Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wheat_seeds"},{"id":"minecraft:white_banner","localizedName":"White Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.white_banner"},{"id":"minecraft:white_bed","localizedName":"White Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.white_bed"},{"id":"minecraft:white_carpet","localizedName":"White Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_carpet"},{"id":"minecraft:white_concrete","localizedName":"White Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete"},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete_powder"},{"id":"minecraft:white_dye","localizedName":"White Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.white_dye"},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_glazed_terracotta"},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.white_shulker_box"},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass"},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass_pane"},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_terracotta"},{"id":"minecraft:white_tulip","localizedName":"White Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_tulip"},{"id":"minecraft:white_wool","localizedName":"White Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_wool"},{"id":"minecraft:witch_spawn_egg","localizedName":"Witch Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.witch_spawn_egg"},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wither_rose"},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wither_skeleton_skull"},{"id":"minecraft:wither_skeleton_spawn_egg","localizedName":"Wither Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wither_skeleton_spawn_egg"},{"id":"minecraft:wolf_spawn_egg","localizedName":"Wolf Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wolf_spawn_egg"},{"id":"minecraft:wooden_axe","localizedName":"Wooden Axe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_axe"},{"id":"minecraft:wooden_hoe","localizedName":"Wooden Hoe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_hoe"},{"id":"minecraft:wooden_pickaxe","localizedName":"Wooden Pickaxe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_pickaxe"},{"id":"minecraft:wooden_shovel","localizedName":"Wooden Shovel","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_shovel"},{"id":"minecraft:wooden_sword","localizedName":"Wooden Sword","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_sword"},{"id":"minecraft:writable_book","localizedName":"Book and Quill","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.writable_book"},{"id":"minecraft:written_book","localizedName":"Written Book","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.written_book"},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.yellow_banner"},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_bed"},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_carpet"},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete"},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete_powder"},{"id":"minecraft:yellow_dye","localizedName":"Yellow Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.yellow_dye"},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_glazed_terracotta"},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_shulker_box"},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass"},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass_pane"},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_terracotta"},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_wool"},{"id":"minecraft:zoglin_spawn_egg","localizedName":"Zoglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zoglin_spawn_egg"},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.zombie_head"},{"id":"minecraft:zombie_horse_spawn_egg","localizedName":"Zombie Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_horse_spawn_egg"},{"id":"minecraft:zombie_spawn_egg","localizedName":"Zombie Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_spawn_egg"},{"id":"minecraft:zombie_villager_spawn_egg","localizedName":"Zombie Villager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_villager_spawn_egg"},{"id":"minecraft:zombified_piglin_spawn_egg","localizedName":"Zombified Piglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombified_piglin_spawn_egg"}] \ No newline at end of file diff --git a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.117.json b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.117.json deleted file mode 100644 index ed74d4d09..000000000 --- a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.117.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":"minecraft:acacia_boat","localizedName":"Acacia Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.acacia_boat"},{"id":"minecraft:acacia_button","localizedName":"Acacia Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_button"},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_door"},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence"},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence_gate"},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_leaves"},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_log"},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_planks"},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_pressure_plate"},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_sapling"},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.acacia_sign"},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_slab"},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_stairs"},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_trapdoor"},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_wood"},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.activator_rail"},{"id":"minecraft:air","localizedName":"Air","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.air"},{"id":"minecraft:allium","localizedName":"Allium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.allium"},{"id":"minecraft:amethyst_block","localizedName":"Block of Amethyst","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.amethyst_block"},{"id":"minecraft:amethyst_cluster","localizedName":"Amethyst Cluster","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.amethyst_cluster"},{"id":"minecraft:amethyst_shard","localizedName":"Amethyst Shard","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.amethyst_shard"},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ancient_debris"},{"id":"minecraft:andesite","localizedName":"Andesite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite"},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_slab"},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_stairs"},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_wall"},{"id":"minecraft:anvil","localizedName":"Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.anvil"},{"id":"minecraft:apple","localizedName":"Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.apple"},{"id":"minecraft:armor_stand","localizedName":"Armor Stand","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.armor_stand"},{"id":"minecraft:arrow","localizedName":"Arrow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.arrow"},{"id":"minecraft:axolotl_bucket","localizedName":"Bucket of Axolotl","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.axolotl_bucket"},{"id":"minecraft:axolotl_spawn_egg","localizedName":"Axolotl Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.axolotl_spawn_egg"},{"id":"minecraft:azalea","localizedName":"Azalea","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.azalea"},{"id":"minecraft:azalea_leaves","localizedName":"Azalea Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.azalea_leaves"},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.azure_bluet"},{"id":"minecraft:baked_potato","localizedName":"Baked Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.baked_potato"},{"id":"minecraft:bamboo","localizedName":"Bamboo","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo"},{"id":"minecraft:barrel","localizedName":"Barrel","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.barrel"},{"id":"minecraft:barrier","localizedName":"Barrier","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.barrier"},{"id":"minecraft:basalt","localizedName":"Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.basalt"},{"id":"minecraft:bat_spawn_egg","localizedName":"Bat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bat_spawn_egg"},{"id":"minecraft:beacon","localizedName":"Beacon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.beacon"},{"id":"minecraft:bedrock","localizedName":"Bedrock","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bedrock"},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bee_nest"},{"id":"minecraft:bee_spawn_egg","localizedName":"Bee Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bee_spawn_egg"},{"id":"minecraft:beef","localizedName":"Raw Beef","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beef"},{"id":"minecraft:beehive","localizedName":"Beehive","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.beehive"},{"id":"minecraft:beetroot","localizedName":"Beetroot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot"},{"id":"minecraft:beetroot_seeds","localizedName":"Beetroot Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot_seeds"},{"id":"minecraft:beetroot_soup","localizedName":"Beetroot Soup","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.beetroot_soup"},{"id":"minecraft:bell","localizedName":"Bell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bell"},{"id":"minecraft:big_dripleaf","localizedName":"Big Dripleaf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.big_dripleaf"},{"id":"minecraft:birch_boat","localizedName":"Birch Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.birch_boat"},{"id":"minecraft:birch_button","localizedName":"Birch Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_button"},{"id":"minecraft:birch_door","localizedName":"Birch Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_door"},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence"},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence_gate"},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_leaves"},{"id":"minecraft:birch_log","localizedName":"Birch Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_log"},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_planks"},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_pressure_plate"},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_sapling"},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.birch_sign"},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_slab"},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_stairs"},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_trapdoor"},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_wood"},{"id":"minecraft:black_banner","localizedName":"Black Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.black_banner"},{"id":"minecraft:black_bed","localizedName":"Black Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.black_bed"},{"id":"minecraft:black_candle","localizedName":"Black Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_candle"},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_carpet"},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete"},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete_powder"},{"id":"minecraft:black_dye","localizedName":"Black Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.black_dye"},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_glazed_terracotta"},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.black_shulker_box"},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass"},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass_pane"},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_terracotta"},{"id":"minecraft:black_wool","localizedName":"Black Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_wool"},{"id":"minecraft:blackstone","localizedName":"Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone"},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_slab"},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_stairs"},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_wall"},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blast_furnace"},{"id":"minecraft:blaze_powder","localizedName":"Blaze Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_powder"},{"id":"minecraft:blaze_rod","localizedName":"Blaze Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_rod"},{"id":"minecraft:blaze_spawn_egg","localizedName":"Blaze Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_spawn_egg"},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.blue_banner"},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.blue_bed"},{"id":"minecraft:blue_candle","localizedName":"Blue Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_candle"},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_carpet"},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete"},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete_powder"},{"id":"minecraft:blue_dye","localizedName":"Blue Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blue_dye"},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_glazed_terracotta"},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_ice"},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_orchid"},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.blue_shulker_box"},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass"},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass_pane"},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_terracotta"},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_wool"},{"id":"minecraft:bone","localizedName":"Bone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bone"},{"id":"minecraft:bone_block","localizedName":"Bone Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bone_block"},{"id":"minecraft:bone_meal","localizedName":"Bone Meal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bone_meal"},{"id":"minecraft:book","localizedName":"Book","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.book"},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bookshelf"},{"id":"minecraft:bow","localizedName":"Bow","maxDamage":384,"maxStackSize":1,"unlocalizedName":"item.minecraft.bow"},{"id":"minecraft:bowl","localizedName":"Bowl","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bowl"},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral"},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_block"},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_fan"},{"id":"minecraft:bread","localizedName":"Bread","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bread"},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brewing_stand"},{"id":"minecraft:brick","localizedName":"Brick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.brick"},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_slab"},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_stairs"},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_wall"},{"id":"minecraft:bricks","localizedName":"Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bricks"},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.brown_banner"},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.brown_bed"},{"id":"minecraft:brown_candle","localizedName":"Brown Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_candle"},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_carpet"},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete"},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete_powder"},{"id":"minecraft:brown_dye","localizedName":"Brown Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.brown_dye"},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_glazed_terracotta"},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom"},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom_block"},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.brown_shulker_box"},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass"},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass_pane"},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_terracotta"},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_wool"},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral"},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_block"},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_fan"},{"id":"minecraft:bucket","localizedName":"Bucket","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.bucket"},{"id":"minecraft:budding_amethyst","localizedName":"Budding Amethyst","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.budding_amethyst"},{"id":"minecraft:bundle","localizedName":"Bundle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.bundle"},{"id":"minecraft:cactus","localizedName":"Cactus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cactus"},{"id":"minecraft:cake","localizedName":"Cake","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cake"},{"id":"minecraft:calcite","localizedName":"Calcite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.calcite"},{"id":"minecraft:campfire","localizedName":"Campfire","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.campfire"},{"id":"minecraft:candle","localizedName":"Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.candle"},{"id":"minecraft:carrot","localizedName":"Carrot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.carrot"},{"id":"minecraft:carrot_on_a_stick","localizedName":"Carrot on a Stick","maxDamage":25,"maxStackSize":1,"unlocalizedName":"item.minecraft.carrot_on_a_stick"},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cartography_table"},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.carved_pumpkin"},{"id":"minecraft:cat_spawn_egg","localizedName":"Cat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cat_spawn_egg"},{"id":"minecraft:cauldron","localizedName":"Cauldron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cauldron"},{"id":"minecraft:cave_spider_spawn_egg","localizedName":"Cave Spider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cave_spider_spawn_egg"},{"id":"minecraft:chain","localizedName":"Chain","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chain"},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chain_command_block"},{"id":"minecraft:chainmail_boots","localizedName":"Chainmail Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_boots"},{"id":"minecraft:chainmail_chestplate","localizedName":"Chainmail Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_chestplate"},{"id":"minecraft:chainmail_helmet","localizedName":"Chainmail Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_helmet"},{"id":"minecraft:chainmail_leggings","localizedName":"Chainmail Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_leggings"},{"id":"minecraft:charcoal","localizedName":"Charcoal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.charcoal"},{"id":"minecraft:chest","localizedName":"Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chest"},{"id":"minecraft:chest_minecart","localizedName":"Minecart with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.chest_minecart"},{"id":"minecraft:chicken","localizedName":"Raw Chicken","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chicken"},{"id":"minecraft:chicken_spawn_egg","localizedName":"Chicken Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chicken_spawn_egg"},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chipped_anvil"},{"id":"minecraft:chiseled_deepslate","localizedName":"Chiseled Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_deepslate"},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_nether_bricks"},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_polished_blackstone"},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_quartz_block"},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_red_sandstone"},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_sandstone"},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_stone_bricks"},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_flower"},{"id":"minecraft:chorus_fruit","localizedName":"Chorus Fruit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chorus_fruit"},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_plant"},{"id":"minecraft:clay","localizedName":"Clay","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.clay"},{"id":"minecraft:clay_ball","localizedName":"Clay Ball","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.clay_ball"},{"id":"minecraft:clock","localizedName":"Clock","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.clock"},{"id":"minecraft:coal","localizedName":"Coal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.coal"},{"id":"minecraft:coal_block","localizedName":"Block of Coal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coal_block"},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coal_ore"},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coarse_dirt"},{"id":"minecraft:cobbled_deepslate","localizedName":"Cobbled Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate"},{"id":"minecraft:cobbled_deepslate_slab","localizedName":"Cobbled Deepslate Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_slab"},{"id":"minecraft:cobbled_deepslate_stairs","localizedName":"Cobbled Deepslate Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_stairs"},{"id":"minecraft:cobbled_deepslate_wall","localizedName":"Cobbled Deepslate Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_wall"},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone"},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_slab"},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_stairs"},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_wall"},{"id":"minecraft:cobweb","localizedName":"Cobweb","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobweb"},{"id":"minecraft:cocoa_beans","localizedName":"Cocoa Beans","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cocoa_beans"},{"id":"minecraft:cod","localizedName":"Raw Cod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cod"},{"id":"minecraft:cod_bucket","localizedName":"Bucket of Cod","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.cod_bucket"},{"id":"minecraft:cod_spawn_egg","localizedName":"Cod Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cod_spawn_egg"},{"id":"minecraft:command_block","localizedName":"Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.command_block"},{"id":"minecraft:command_block_minecart","localizedName":"Minecart with Command Block","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.command_block_minecart"},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.comparator"},{"id":"minecraft:compass","localizedName":"Compass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.compass"},{"id":"minecraft:composter","localizedName":"Composter","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.composter"},{"id":"minecraft:conduit","localizedName":"Conduit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.conduit"},{"id":"minecraft:cooked_beef","localizedName":"Steak","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_beef"},{"id":"minecraft:cooked_chicken","localizedName":"Cooked Chicken","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_chicken"},{"id":"minecraft:cooked_cod","localizedName":"Cooked Cod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_cod"},{"id":"minecraft:cooked_mutton","localizedName":"Cooked Mutton","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_mutton"},{"id":"minecraft:cooked_porkchop","localizedName":"Cooked Porkchop","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_porkchop"},{"id":"minecraft:cooked_rabbit","localizedName":"Cooked Rabbit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_rabbit"},{"id":"minecraft:cooked_salmon","localizedName":"Cooked Salmon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_salmon"},{"id":"minecraft:cookie","localizedName":"Cookie","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cookie"},{"id":"minecraft:copper_block","localizedName":"Block of Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.copper_block"},{"id":"minecraft:copper_ingot","localizedName":"Copper Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.copper_ingot"},{"id":"minecraft:copper_ore","localizedName":"Copper Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.copper_ore"},{"id":"minecraft:cornflower","localizedName":"Cornflower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cornflower"},{"id":"minecraft:cow_spawn_egg","localizedName":"Cow Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cow_spawn_egg"},{"id":"minecraft:cracked_deepslate_bricks","localizedName":"Cracked Deepslate Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_deepslate_bricks"},{"id":"minecraft:cracked_deepslate_tiles","localizedName":"Cracked Deepslate Tiles","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_deepslate_tiles"},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_nether_bricks"},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_polished_blackstone_bricks"},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_stone_bricks"},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crafting_table"},{"id":"minecraft:creeper_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.creeper_banner_pattern"},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.creeper_head"},{"id":"minecraft:creeper_spawn_egg","localizedName":"Creeper Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.creeper_spawn_egg"},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_button"},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_door"},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence"},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence_gate"},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fungus"},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_hyphae"},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_nylium"},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_planks"},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_pressure_plate"},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_roots"},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.crimson_sign"},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_slab"},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stairs"},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stem"},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_trapdoor"},{"id":"minecraft:crossbow","localizedName":"Crossbow","maxDamage":326,"maxStackSize":1,"unlocalizedName":"item.minecraft.crossbow"},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crying_obsidian"},{"id":"minecraft:cut_copper","localizedName":"Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper"},{"id":"minecraft:cut_copper_slab","localizedName":"Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper_slab"},{"id":"minecraft:cut_copper_stairs","localizedName":"Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper_stairs"},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone"},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone_slab"},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone"},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone_slab"},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.cyan_banner"},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_bed"},{"id":"minecraft:cyan_candle","localizedName":"Cyan Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_candle"},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_carpet"},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete"},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete_powder"},{"id":"minecraft:cyan_dye","localizedName":"Cyan Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cyan_dye"},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_glazed_terracotta"},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_shulker_box"},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass"},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass_pane"},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_terracotta"},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_wool"},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.damaged_anvil"},{"id":"minecraft:dandelion","localizedName":"Dandelion","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dandelion"},{"id":"minecraft:dark_oak_boat","localizedName":"Dark Oak Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.dark_oak_boat"},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_button"},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_door"},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence"},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence_gate"},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_leaves"},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_log"},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_planks"},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_pressure_plate"},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_sapling"},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.dark_oak_sign"},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_slab"},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_stairs"},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_trapdoor"},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_wood"},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine"},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_slab"},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_stairs"},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.daylight_detector"},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral"},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_block"},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_fan"},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral"},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_block"},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_fan"},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bush"},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral"},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_block"},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_fan"},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral"},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_block"},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_fan"},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral"},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_block"},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_fan"},{"id":"minecraft:debug_stick","localizedName":"Debug Stick","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.debug_stick"},{"id":"minecraft:deepslate","localizedName":"Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate"},{"id":"minecraft:deepslate_brick_slab","localizedName":"Deepslate Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_slab"},{"id":"minecraft:deepslate_brick_stairs","localizedName":"Deepslate Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_stairs"},{"id":"minecraft:deepslate_brick_wall","localizedName":"Deepslate Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_wall"},{"id":"minecraft:deepslate_bricks","localizedName":"Deepslate Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_bricks"},{"id":"minecraft:deepslate_coal_ore","localizedName":"Deepslate Coal Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_coal_ore"},{"id":"minecraft:deepslate_copper_ore","localizedName":"Deepslate Copper Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_copper_ore"},{"id":"minecraft:deepslate_diamond_ore","localizedName":"Deepslate Diamond Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_diamond_ore"},{"id":"minecraft:deepslate_emerald_ore","localizedName":"Deepslate Emerald Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_emerald_ore"},{"id":"minecraft:deepslate_gold_ore","localizedName":"Deepslate Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_gold_ore"},{"id":"minecraft:deepslate_iron_ore","localizedName":"Deepslate Iron Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_iron_ore"},{"id":"minecraft:deepslate_lapis_ore","localizedName":"Deepslate Lapis Lazuli Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_lapis_ore"},{"id":"minecraft:deepslate_redstone_ore","localizedName":"Deepslate Redstone Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_redstone_ore"},{"id":"minecraft:deepslate_tile_slab","localizedName":"Deepslate Tile Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_slab"},{"id":"minecraft:deepslate_tile_stairs","localizedName":"Deepslate Tile Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_stairs"},{"id":"minecraft:deepslate_tile_wall","localizedName":"Deepslate Tile Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_wall"},{"id":"minecraft:deepslate_tiles","localizedName":"Deepslate Tiles","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tiles"},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.detector_rail"},{"id":"minecraft:diamond","localizedName":"Diamond","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.diamond"},{"id":"minecraft:diamond_axe","localizedName":"Diamond Axe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_axe"},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_block"},{"id":"minecraft:diamond_boots","localizedName":"Diamond Boots","maxDamage":429,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_boots"},{"id":"minecraft:diamond_chestplate","localizedName":"Diamond Chestplate","maxDamage":528,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_chestplate"},{"id":"minecraft:diamond_helmet","localizedName":"Diamond Helmet","maxDamage":363,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_helmet"},{"id":"minecraft:diamond_hoe","localizedName":"Diamond Hoe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_hoe"},{"id":"minecraft:diamond_horse_armor","localizedName":"Diamond Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_horse_armor"},{"id":"minecraft:diamond_leggings","localizedName":"Diamond Leggings","maxDamage":495,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_leggings"},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_ore"},{"id":"minecraft:diamond_pickaxe","localizedName":"Diamond Pickaxe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_pickaxe"},{"id":"minecraft:diamond_shovel","localizedName":"Diamond Shovel","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_shovel"},{"id":"minecraft:diamond_sword","localizedName":"Diamond Sword","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_sword"},{"id":"minecraft:diorite","localizedName":"Diorite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite"},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_slab"},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_stairs"},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_wall"},{"id":"minecraft:dirt","localizedName":"Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dirt"},{"id":"minecraft:dirt_path","localizedName":"Dirt Path","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dirt_path"},{"id":"minecraft:dispenser","localizedName":"Dispenser","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dispenser"},{"id":"minecraft:dolphin_spawn_egg","localizedName":"Dolphin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dolphin_spawn_egg"},{"id":"minecraft:donkey_spawn_egg","localizedName":"Donkey Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.donkey_spawn_egg"},{"id":"minecraft:dragon_breath","localizedName":"Dragon\u0027s Breath","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dragon_breath"},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_egg"},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_head"},{"id":"minecraft:dried_kelp","localizedName":"Dried Kelp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dried_kelp"},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dried_kelp_block"},{"id":"minecraft:dripstone_block","localizedName":"Dripstone Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dripstone_block"},{"id":"minecraft:dropper","localizedName":"Dropper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dropper"},{"id":"minecraft:drowned_spawn_egg","localizedName":"Drowned Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.drowned_spawn_egg"},{"id":"minecraft:egg","localizedName":"Egg","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.egg"},{"id":"minecraft:elder_guardian_spawn_egg","localizedName":"Elder Guardian Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.elder_guardian_spawn_egg"},{"id":"minecraft:elytra","localizedName":"Elytra","maxDamage":432,"maxStackSize":1,"unlocalizedName":"item.minecraft.elytra"},{"id":"minecraft:emerald","localizedName":"Emerald","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.emerald"},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_block"},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_ore"},{"id":"minecraft:enchanted_book","localizedName":"Enchanted Book","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.enchanted_book"},{"id":"minecraft:enchanted_golden_apple","localizedName":"Enchanted Golden Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.enchanted_golden_apple"},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.enchanting_table"},{"id":"minecraft:end_crystal","localizedName":"End Crystal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.end_crystal"},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_portal_frame"},{"id":"minecraft:end_rod","localizedName":"End Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_rod"},{"id":"minecraft:end_stone","localizedName":"End Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone"},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_slab"},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_stairs"},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_wall"},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_bricks"},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ender_chest"},{"id":"minecraft:ender_eye","localizedName":"Eye of Ender","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ender_eye"},{"id":"minecraft:ender_pearl","localizedName":"Ender Pearl","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.ender_pearl"},{"id":"minecraft:enderman_spawn_egg","localizedName":"Enderman Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.enderman_spawn_egg"},{"id":"minecraft:endermite_spawn_egg","localizedName":"Endermite Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.endermite_spawn_egg"},{"id":"minecraft:evoker_spawn_egg","localizedName":"Evoker Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.evoker_spawn_egg"},{"id":"minecraft:experience_bottle","localizedName":"Bottle o\u0027 Enchanting","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.experience_bottle"},{"id":"minecraft:exposed_copper","localizedName":"Exposed Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_copper"},{"id":"minecraft:exposed_cut_copper","localizedName":"Exposed Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper"},{"id":"minecraft:exposed_cut_copper_slab","localizedName":"Exposed Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper_slab"},{"id":"minecraft:exposed_cut_copper_stairs","localizedName":"Exposed Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper_stairs"},{"id":"minecraft:farmland","localizedName":"Farmland","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.farmland"},{"id":"minecraft:feather","localizedName":"Feather","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.feather"},{"id":"minecraft:fermented_spider_eye","localizedName":"Fermented Spider Eye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fermented_spider_eye"},{"id":"minecraft:fern","localizedName":"Fern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fern"},{"id":"minecraft:filled_map","localizedName":"Map","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.filled_map"},{"id":"minecraft:fire_charge","localizedName":"Fire Charge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fire_charge"},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral"},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_block"},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_fan"},{"id":"minecraft:firework_rocket","localizedName":"Firework Rocket","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.firework_rocket"},{"id":"minecraft:firework_star","localizedName":"Firework Star","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.firework_star"},{"id":"minecraft:fishing_rod","localizedName":"Fishing Rod","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.fishing_rod"},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fletching_table"},{"id":"minecraft:flint","localizedName":"Flint","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.flint"},{"id":"minecraft:flint_and_steel","localizedName":"Flint and Steel","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.flint_and_steel"},{"id":"minecraft:flower_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.flower_banner_pattern"},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.flower_pot"},{"id":"minecraft:flowering_azalea","localizedName":"Flowering Azalea","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.flowering_azalea"},{"id":"minecraft:flowering_azalea_leaves","localizedName":"Flowering Azalea Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.flowering_azalea_leaves"},{"id":"minecraft:fox_spawn_egg","localizedName":"Fox Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fox_spawn_egg"},{"id":"minecraft:furnace","localizedName":"Furnace","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.furnace"},{"id":"minecraft:furnace_minecart","localizedName":"Minecart with Furnace","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.furnace_minecart"},{"id":"minecraft:ghast_spawn_egg","localizedName":"Ghast Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_spawn_egg"},{"id":"minecraft:ghast_tear","localizedName":"Ghast Tear","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_tear"},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gilded_blackstone"},{"id":"minecraft:glass","localizedName":"Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glass"},{"id":"minecraft:glass_bottle","localizedName":"Glass Bottle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glass_bottle"},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glass_pane"},{"id":"minecraft:glistering_melon_slice","localizedName":"Glistering Melon Slice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glistering_melon_slice"},{"id":"minecraft:globe_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.globe_banner_pattern"},{"id":"minecraft:glow_berries","localizedName":"Glow Berries","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_berries"},{"id":"minecraft:glow_ink_sac","localizedName":"Glow Ink Sac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_ink_sac"},{"id":"minecraft:glow_item_frame","localizedName":"Glow Item Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_item_frame"},{"id":"minecraft:glow_lichen","localizedName":"Glow Lichen","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glow_lichen"},{"id":"minecraft:glow_squid_spawn_egg","localizedName":"Glow Squid Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_squid_spawn_egg"},{"id":"minecraft:glowstone","localizedName":"Glowstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glowstone"},{"id":"minecraft:glowstone_dust","localizedName":"Glowstone Dust","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glowstone_dust"},{"id":"minecraft:goat_spawn_egg","localizedName":"Goat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.goat_spawn_egg"},{"id":"minecraft:gold_block","localizedName":"Block of Gold","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gold_block"},{"id":"minecraft:gold_ingot","localizedName":"Gold Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gold_ingot"},{"id":"minecraft:gold_nugget","localizedName":"Gold Nugget","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gold_nugget"},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gold_ore"},{"id":"minecraft:golden_apple","localizedName":"Golden Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.golden_apple"},{"id":"minecraft:golden_axe","localizedName":"Golden Axe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_axe"},{"id":"minecraft:golden_boots","localizedName":"Golden Boots","maxDamage":91,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_boots"},{"id":"minecraft:golden_carrot","localizedName":"Golden Carrot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.golden_carrot"},{"id":"minecraft:golden_chestplate","localizedName":"Golden Chestplate","maxDamage":112,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_chestplate"},{"id":"minecraft:golden_helmet","localizedName":"Golden Helmet","maxDamage":77,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_helmet"},{"id":"minecraft:golden_hoe","localizedName":"Golden Hoe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_hoe"},{"id":"minecraft:golden_horse_armor","localizedName":"Golden Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_horse_armor"},{"id":"minecraft:golden_leggings","localizedName":"Golden Leggings","maxDamage":105,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_leggings"},{"id":"minecraft:golden_pickaxe","localizedName":"Golden Pickaxe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_pickaxe"},{"id":"minecraft:golden_shovel","localizedName":"Golden Shovel","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_shovel"},{"id":"minecraft:golden_sword","localizedName":"Golden Sword","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_sword"},{"id":"minecraft:granite","localizedName":"Granite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite"},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_slab"},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_stairs"},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_wall"},{"id":"minecraft:grass","localizedName":"Grass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grass"},{"id":"minecraft:grass_block","localizedName":"Grass Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grass_block"},{"id":"minecraft:gravel","localizedName":"Gravel","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gravel"},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.gray_banner"},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.gray_bed"},{"id":"minecraft:gray_candle","localizedName":"Gray Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_candle"},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_carpet"},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete"},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete_powder"},{"id":"minecraft:gray_dye","localizedName":"Gray Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gray_dye"},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_glazed_terracotta"},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.gray_shulker_box"},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass"},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass_pane"},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_terracotta"},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_wool"},{"id":"minecraft:green_banner","localizedName":"Green Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.green_banner"},{"id":"minecraft:green_bed","localizedName":"Green Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.green_bed"},{"id":"minecraft:green_candle","localizedName":"Green Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_candle"},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_carpet"},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete"},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete_powder"},{"id":"minecraft:green_dye","localizedName":"Green Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.green_dye"},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_glazed_terracotta"},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.green_shulker_box"},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass"},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass_pane"},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_terracotta"},{"id":"minecraft:green_wool","localizedName":"Green Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_wool"},{"id":"minecraft:grindstone","localizedName":"Grindstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grindstone"},{"id":"minecraft:guardian_spawn_egg","localizedName":"Guardian Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.guardian_spawn_egg"},{"id":"minecraft:gunpowder","localizedName":"Gunpowder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gunpowder"},{"id":"minecraft:hanging_roots","localizedName":"Hanging Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hanging_roots"},{"id":"minecraft:hay_block","localizedName":"Hay Bale","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hay_block"},{"id":"minecraft:heart_of_the_sea","localizedName":"Heart of the Sea","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.heart_of_the_sea"},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.heavy_weighted_pressure_plate"},{"id":"minecraft:hoglin_spawn_egg","localizedName":"Hoglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.hoglin_spawn_egg"},{"id":"minecraft:honey_block","localizedName":"Honey Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.honey_block"},{"id":"minecraft:honey_bottle","localizedName":"Honey Bottle","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.honey_bottle"},{"id":"minecraft:honeycomb","localizedName":"Honeycomb","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.honeycomb"},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.honeycomb_block"},{"id":"minecraft:hopper","localizedName":"Hopper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hopper"},{"id":"minecraft:hopper_minecart","localizedName":"Minecart with Hopper","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.hopper_minecart"},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral"},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_block"},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_fan"},{"id":"minecraft:horse_spawn_egg","localizedName":"Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.horse_spawn_egg"},{"id":"minecraft:husk_spawn_egg","localizedName":"Husk Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.husk_spawn_egg"},{"id":"minecraft:ice","localizedName":"Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ice"},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_chiseled_stone_bricks"},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cobblestone"},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cracked_stone_bricks"},{"id":"minecraft:infested_deepslate","localizedName":"Infested Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_deepslate"},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_mossy_stone_bricks"},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone"},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone_bricks"},{"id":"minecraft:ink_sac","localizedName":"Ink Sac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ink_sac"},{"id":"minecraft:iron_axe","localizedName":"Iron Axe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_axe"},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_bars"},{"id":"minecraft:iron_block","localizedName":"Block of Iron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_block"},{"id":"minecraft:iron_boots","localizedName":"Iron Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_boots"},{"id":"minecraft:iron_chestplate","localizedName":"Iron Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_chestplate"},{"id":"minecraft:iron_door","localizedName":"Iron Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_door"},{"id":"minecraft:iron_helmet","localizedName":"Iron Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_helmet"},{"id":"minecraft:iron_hoe","localizedName":"Iron Hoe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_hoe"},{"id":"minecraft:iron_horse_armor","localizedName":"Iron Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_horse_armor"},{"id":"minecraft:iron_ingot","localizedName":"Iron Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.iron_ingot"},{"id":"minecraft:iron_leggings","localizedName":"Iron Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_leggings"},{"id":"minecraft:iron_nugget","localizedName":"Iron Nugget","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.iron_nugget"},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_ore"},{"id":"minecraft:iron_pickaxe","localizedName":"Iron Pickaxe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_pickaxe"},{"id":"minecraft:iron_shovel","localizedName":"Iron Shovel","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_shovel"},{"id":"minecraft:iron_sword","localizedName":"Iron Sword","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_sword"},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_trapdoor"},{"id":"minecraft:item_frame","localizedName":"Item Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.item_frame"},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o\u0027Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jack_o_lantern"},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jigsaw"},{"id":"minecraft:jukebox","localizedName":"Jukebox","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jukebox"},{"id":"minecraft:jungle_boat","localizedName":"Jungle Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.jungle_boat"},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_button"},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_door"},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence"},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence_gate"},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_leaves"},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_log"},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_planks"},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_pressure_plate"},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_sapling"},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.jungle_sign"},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_slab"},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_stairs"},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_trapdoor"},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_wood"},{"id":"minecraft:kelp","localizedName":"Kelp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.kelp"},{"id":"minecraft:knowledge_book","localizedName":"Knowledge Book","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.knowledge_book"},{"id":"minecraft:ladder","localizedName":"Ladder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ladder"},{"id":"minecraft:lantern","localizedName":"Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lantern"},{"id":"minecraft:lapis_block","localizedName":"Block of Lapis Lazuli","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_block"},{"id":"minecraft:lapis_lazuli","localizedName":"Lapis Lazuli","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lapis_lazuli"},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_ore"},{"id":"minecraft:large_amethyst_bud","localizedName":"Large Amethyst Bud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.large_amethyst_bud"},{"id":"minecraft:large_fern","localizedName":"Large Fern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.large_fern"},{"id":"minecraft:lava_bucket","localizedName":"Lava Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.lava_bucket"},{"id":"minecraft:lead","localizedName":"Lead","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lead"},{"id":"minecraft:leather","localizedName":"Leather","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.leather"},{"id":"minecraft:leather_boots","localizedName":"Leather Boots","maxDamage":65,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_boots"},{"id":"minecraft:leather_chestplate","localizedName":"Leather Tunic","maxDamage":80,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_chestplate"},{"id":"minecraft:leather_helmet","localizedName":"Leather Cap","maxDamage":55,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_helmet"},{"id":"minecraft:leather_horse_armor","localizedName":"Leather Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_horse_armor"},{"id":"minecraft:leather_leggings","localizedName":"Leather Pants","maxDamage":75,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_leggings"},{"id":"minecraft:lectern","localizedName":"Lectern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lectern"},{"id":"minecraft:lever","localizedName":"Lever","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lever"},{"id":"minecraft:light","localizedName":"Light","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light"},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.light_blue_banner"},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_bed"},{"id":"minecraft:light_blue_candle","localizedName":"Light Blue Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_candle"},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_carpet"},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete"},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete_powder"},{"id":"minecraft:light_blue_dye","localizedName":"Light Blue Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.light_blue_dye"},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_glazed_terracotta"},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_shulker_box"},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass"},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass_pane"},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_terracotta"},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_wool"},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.light_gray_banner"},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_bed"},{"id":"minecraft:light_gray_candle","localizedName":"Light Gray Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_candle"},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_carpet"},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete"},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete_powder"},{"id":"minecraft:light_gray_dye","localizedName":"Light Gray Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.light_gray_dye"},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_glazed_terracotta"},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_shulker_box"},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass"},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass_pane"},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_terracotta"},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_wool"},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_weighted_pressure_plate"},{"id":"minecraft:lightning_rod","localizedName":"Lightning Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lightning_rod"},{"id":"minecraft:lilac","localizedName":"Lilac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lilac"},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lily_of_the_valley"},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lily_pad"},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.lime_banner"},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.lime_bed"},{"id":"minecraft:lime_candle","localizedName":"Lime Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_candle"},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_carpet"},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete"},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete_powder"},{"id":"minecraft:lime_dye","localizedName":"Lime Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lime_dye"},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_glazed_terracotta"},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.lime_shulker_box"},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass"},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass_pane"},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_terracotta"},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_wool"},{"id":"minecraft:lingering_potion","localizedName":"Lingering Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.lingering_potion.effect.water"},{"id":"minecraft:llama_spawn_egg","localizedName":"Llama Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.llama_spawn_egg"},{"id":"minecraft:lodestone","localizedName":"Lodestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lodestone"},{"id":"minecraft:loom","localizedName":"Loom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.loom"},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.magenta_banner"},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_bed"},{"id":"minecraft:magenta_candle","localizedName":"Magenta Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_candle"},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_carpet"},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete"},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete_powder"},{"id":"minecraft:magenta_dye","localizedName":"Magenta Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magenta_dye"},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_glazed_terracotta"},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_shulker_box"},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass"},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass_pane"},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_terracotta"},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_wool"},{"id":"minecraft:magma_block","localizedName":"Magma Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magma_block"},{"id":"minecraft:magma_cream","localizedName":"Magma Cream","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cream"},{"id":"minecraft:magma_cube_spawn_egg","localizedName":"Magma Cube Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cube_spawn_egg"},{"id":"minecraft:map","localizedName":"Empty Map","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.map"},{"id":"minecraft:medium_amethyst_bud","localizedName":"Medium Amethyst Bud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.medium_amethyst_bud"},{"id":"minecraft:melon","localizedName":"Melon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.melon"},{"id":"minecraft:melon_seeds","localizedName":"Melon Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.melon_seeds"},{"id":"minecraft:melon_slice","localizedName":"Melon Slice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.melon_slice"},{"id":"minecraft:milk_bucket","localizedName":"Milk Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.milk_bucket"},{"id":"minecraft:minecart","localizedName":"Minecart","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.minecart"},{"id":"minecraft:mojang_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mojang_banner_pattern"},{"id":"minecraft:mooshroom_spawn_egg","localizedName":"Mooshroom Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mooshroom_spawn_egg"},{"id":"minecraft:moss_block","localizedName":"Moss Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.moss_block"},{"id":"minecraft:moss_carpet","localizedName":"Moss Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.moss_carpet"},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone"},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_slab"},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_stairs"},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_wall"},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_slab"},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_stairs"},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_wall"},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_bricks"},{"id":"minecraft:mule_spawn_egg","localizedName":"Mule Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mule_spawn_egg"},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mushroom_stem"},{"id":"minecraft:mushroom_stew","localizedName":"Mushroom Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mushroom_stew"},{"id":"minecraft:music_disc_11","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_11"},{"id":"minecraft:music_disc_13","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_13"},{"id":"minecraft:music_disc_blocks","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_blocks"},{"id":"minecraft:music_disc_cat","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_cat"},{"id":"minecraft:music_disc_chirp","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_chirp"},{"id":"minecraft:music_disc_far","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_far"},{"id":"minecraft:music_disc_mall","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mall"},{"id":"minecraft:music_disc_mellohi","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mellohi"},{"id":"minecraft:music_disc_pigstep","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_pigstep"},{"id":"minecraft:music_disc_stal","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_stal"},{"id":"minecraft:music_disc_strad","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_strad"},{"id":"minecraft:music_disc_wait","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_wait"},{"id":"minecraft:music_disc_ward","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_ward"},{"id":"minecraft:mutton","localizedName":"Raw Mutton","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mutton"},{"id":"minecraft:mycelium","localizedName":"Mycelium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mycelium"},{"id":"minecraft:name_tag","localizedName":"Name Tag","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.name_tag"},{"id":"minecraft:nautilus_shell","localizedName":"Nautilus Shell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nautilus_shell"},{"id":"minecraft:nether_brick","localizedName":"Nether Brick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_brick"},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_fence"},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_slab"},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_stairs"},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_wall"},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_bricks"},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_gold_ore"},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_quartz_ore"},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_sprouts"},{"id":"minecraft:nether_star","localizedName":"Nether Star","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_star"},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_wart"},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_wart_block"},{"id":"minecraft:netherite_axe","localizedName":"Netherite Axe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_axe"},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.netherite_block"},{"id":"minecraft:netherite_boots","localizedName":"Netherite Boots","maxDamage":481,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_boots"},{"id":"minecraft:netherite_chestplate","localizedName":"Netherite Chestplate","maxDamage":592,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_chestplate"},{"id":"minecraft:netherite_helmet","localizedName":"Netherite Helmet","maxDamage":407,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_helmet"},{"id":"minecraft:netherite_hoe","localizedName":"Netherite Hoe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_hoe"},{"id":"minecraft:netherite_ingot","localizedName":"Netherite Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_ingot"},{"id":"minecraft:netherite_leggings","localizedName":"Netherite Leggings","maxDamage":555,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_leggings"},{"id":"minecraft:netherite_pickaxe","localizedName":"Netherite Pickaxe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_pickaxe"},{"id":"minecraft:netherite_scrap","localizedName":"Netherite Scrap","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_scrap"},{"id":"minecraft:netherite_shovel","localizedName":"Netherite Shovel","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_shovel"},{"id":"minecraft:netherite_sword","localizedName":"Netherite Sword","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_sword"},{"id":"minecraft:netherrack","localizedName":"Netherrack","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.netherrack"},{"id":"minecraft:note_block","localizedName":"Note Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.note_block"},{"id":"minecraft:oak_boat","localizedName":"Oak Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.oak_boat"},{"id":"minecraft:oak_button","localizedName":"Oak Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_button"},{"id":"minecraft:oak_door","localizedName":"Oak Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_door"},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence"},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence_gate"},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_leaves"},{"id":"minecraft:oak_log","localizedName":"Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_log"},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_planks"},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_pressure_plate"},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_sapling"},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.oak_sign"},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_slab"},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_stairs"},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_trapdoor"},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_wood"},{"id":"minecraft:observer","localizedName":"Observer","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.observer"},{"id":"minecraft:obsidian","localizedName":"Obsidian","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.obsidian"},{"id":"minecraft:ocelot_spawn_egg","localizedName":"Ocelot Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ocelot_spawn_egg"},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.orange_banner"},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.orange_bed"},{"id":"minecraft:orange_candle","localizedName":"Orange Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_candle"},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_carpet"},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete"},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete_powder"},{"id":"minecraft:orange_dye","localizedName":"Orange Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.orange_dye"},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_glazed_terracotta"},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.orange_shulker_box"},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass"},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass_pane"},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_terracotta"},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_tulip"},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_wool"},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxeye_daisy"},{"id":"minecraft:oxidized_copper","localizedName":"Oxidized Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_copper"},{"id":"minecraft:oxidized_cut_copper","localizedName":"Oxidized Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper"},{"id":"minecraft:oxidized_cut_copper_slab","localizedName":"Oxidized Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper_slab"},{"id":"minecraft:oxidized_cut_copper_stairs","localizedName":"Oxidized Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper_stairs"},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.packed_ice"},{"id":"minecraft:painting","localizedName":"Painting","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.painting"},{"id":"minecraft:panda_spawn_egg","localizedName":"Panda Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.panda_spawn_egg"},{"id":"minecraft:paper","localizedName":"Paper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.paper"},{"id":"minecraft:parrot_spawn_egg","localizedName":"Parrot Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.parrot_spawn_egg"},{"id":"minecraft:peony","localizedName":"Peony","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.peony"},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.petrified_oak_slab"},{"id":"minecraft:phantom_membrane","localizedName":"Phantom Membrane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_membrane"},{"id":"minecraft:phantom_spawn_egg","localizedName":"Phantom Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_spawn_egg"},{"id":"minecraft:pig_spawn_egg","localizedName":"Pig Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pig_spawn_egg"},{"id":"minecraft:piglin_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.piglin_banner_pattern"},{"id":"minecraft:piglin_brute_spawn_egg","localizedName":"Piglin Brute Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_brute_spawn_egg"},{"id":"minecraft:piglin_spawn_egg","localizedName":"Piglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_spawn_egg"},{"id":"minecraft:pillager_spawn_egg","localizedName":"Pillager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pillager_spawn_egg"},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.pink_banner"},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.pink_bed"},{"id":"minecraft:pink_candle","localizedName":"Pink Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_candle"},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_carpet"},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete"},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete_powder"},{"id":"minecraft:pink_dye","localizedName":"Pink Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pink_dye"},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_glazed_terracotta"},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.pink_shulker_box"},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass"},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass_pane"},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_terracotta"},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_tulip"},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_wool"},{"id":"minecraft:piston","localizedName":"Piston","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.piston"},{"id":"minecraft:player_head","localizedName":"Player Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.player_head"},{"id":"minecraft:podzol","localizedName":"Podzol","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.podzol"},{"id":"minecraft:pointed_dripstone","localizedName":"Pointed Dripstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pointed_dripstone"},{"id":"minecraft:poisonous_potato","localizedName":"Poisonous Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.poisonous_potato"},{"id":"minecraft:polar_bear_spawn_egg","localizedName":"Polar Bear Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.polar_bear_spawn_egg"},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite"},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_slab"},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_stairs"},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_basalt"},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone"},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_slab"},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_stairs"},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_wall"},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_bricks"},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_button"},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_pressure_plate"},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_slab"},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_stairs"},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_wall"},{"id":"minecraft:polished_deepslate","localizedName":"Polished Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate"},{"id":"minecraft:polished_deepslate_slab","localizedName":"Polished Deepslate Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_slab"},{"id":"minecraft:polished_deepslate_stairs","localizedName":"Polished Deepslate Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_stairs"},{"id":"minecraft:polished_deepslate_wall","localizedName":"Polished Deepslate Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_wall"},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite"},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_slab"},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_stairs"},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite"},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_slab"},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_stairs"},{"id":"minecraft:popped_chorus_fruit","localizedName":"Popped Chorus Fruit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.popped_chorus_fruit"},{"id":"minecraft:poppy","localizedName":"Poppy","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.poppy"},{"id":"minecraft:porkchop","localizedName":"Raw Porkchop","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.porkchop"},{"id":"minecraft:potato","localizedName":"Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.potato"},{"id":"minecraft:potion","localizedName":"Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.potion.effect.water"},{"id":"minecraft:powder_snow_bucket","localizedName":"Powder Snow Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.powder_snow_bucket"},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.powered_rail"},{"id":"minecraft:prismarine","localizedName":"Prismarine","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine"},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_slab"},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_stairs"},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_bricks"},{"id":"minecraft:prismarine_crystals","localizedName":"Prismarine Crystals","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_crystals"},{"id":"minecraft:prismarine_shard","localizedName":"Prismarine Shard","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_shard"},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_slab"},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_stairs"},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_wall"},{"id":"minecraft:pufferfish","localizedName":"Pufferfish","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish"},{"id":"minecraft:pufferfish_bucket","localizedName":"Bucket of Pufferfish","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.pufferfish_bucket"},{"id":"minecraft:pufferfish_spawn_egg","localizedName":"Pufferfish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish_spawn_egg"},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pumpkin"},{"id":"minecraft:pumpkin_pie","localizedName":"Pumpkin Pie","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_pie"},{"id":"minecraft:pumpkin_seeds","localizedName":"Pumpkin Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_seeds"},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.purple_banner"},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.purple_bed"},{"id":"minecraft:purple_candle","localizedName":"Purple Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_candle"},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_carpet"},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete"},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete_powder"},{"id":"minecraft:purple_dye","localizedName":"Purple Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.purple_dye"},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_glazed_terracotta"},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.purple_shulker_box"},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass"},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass_pane"},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_terracotta"},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_wool"},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_block"},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_pillar"},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_slab"},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_stairs"},{"id":"minecraft:quartz","localizedName":"Nether Quartz","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.quartz"},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_block"},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_bricks"},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_pillar"},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_slab"},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_stairs"},{"id":"minecraft:rabbit","localizedName":"Raw Rabbit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit"},{"id":"minecraft:rabbit_foot","localizedName":"Rabbit\u0027s Foot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_foot"},{"id":"minecraft:rabbit_hide","localizedName":"Rabbit Hide","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_hide"},{"id":"minecraft:rabbit_spawn_egg","localizedName":"Rabbit Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_spawn_egg"},{"id":"minecraft:rabbit_stew","localizedName":"Rabbit Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.rabbit_stew"},{"id":"minecraft:rail","localizedName":"Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rail"},{"id":"minecraft:ravager_spawn_egg","localizedName":"Ravager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ravager_spawn_egg"},{"id":"minecraft:raw_copper","localizedName":"Raw Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.raw_copper"},{"id":"minecraft:raw_copper_block","localizedName":"Block of Raw Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.raw_copper_block"},{"id":"minecraft:raw_gold","localizedName":"Raw Gold","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.raw_gold"},{"id":"minecraft:raw_gold_block","localizedName":"Block of Raw Gold","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.raw_gold_block"},{"id":"minecraft:raw_iron","localizedName":"Raw Iron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.raw_iron"},{"id":"minecraft:raw_iron_block","localizedName":"Block of Raw Iron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.raw_iron_block"},{"id":"minecraft:red_banner","localizedName":"Red Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.red_banner"},{"id":"minecraft:red_bed","localizedName":"Red Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.red_bed"},{"id":"minecraft:red_candle","localizedName":"Red Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_candle"},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_carpet"},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete"},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete_powder"},{"id":"minecraft:red_dye","localizedName":"Red Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.red_dye"},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_glazed_terracotta"},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom"},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom_block"},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_slab"},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_stairs"},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_wall"},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_bricks"},{"id":"minecraft:red_sand","localizedName":"Red Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sand"},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone"},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_slab"},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_stairs"},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_wall"},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.red_shulker_box"},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass"},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass_pane"},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_terracotta"},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_tulip"},{"id":"minecraft:red_wool","localizedName":"Red Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_wool"},{"id":"minecraft:redstone","localizedName":"Redstone Dust","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.redstone"},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_block"},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_lamp"},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_ore"},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_torch"},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.repeater"},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.repeating_command_block"},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.respawn_anchor"},{"id":"minecraft:rooted_dirt","localizedName":"Rooted Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rooted_dirt"},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rose_bush"},{"id":"minecraft:rotten_flesh","localizedName":"Rotten Flesh","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rotten_flesh"},{"id":"minecraft:saddle","localizedName":"Saddle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.saddle"},{"id":"minecraft:salmon","localizedName":"Raw Salmon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.salmon"},{"id":"minecraft:salmon_bucket","localizedName":"Bucket of Salmon","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.salmon_bucket"},{"id":"minecraft:salmon_spawn_egg","localizedName":"Salmon Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.salmon_spawn_egg"},{"id":"minecraft:sand","localizedName":"Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sand"},{"id":"minecraft:sandstone","localizedName":"Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone"},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_slab"},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_stairs"},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_wall"},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.scaffolding"},{"id":"minecraft:sculk_sensor","localizedName":"Sculk Sensor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_sensor"},{"id":"minecraft:scute","localizedName":"Scute","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.scute"},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sea_lantern"},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sea_pickle"},{"id":"minecraft:seagrass","localizedName":"Seagrass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.seagrass"},{"id":"minecraft:shears","localizedName":"Shears","maxDamage":238,"maxStackSize":1,"unlocalizedName":"item.minecraft.shears"},{"id":"minecraft:sheep_spawn_egg","localizedName":"Sheep Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sheep_spawn_egg"},{"id":"minecraft:shield","localizedName":"Shield","maxDamage":336,"maxStackSize":1,"unlocalizedName":"item.minecraft.shield"},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.shroomlight"},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.shulker_box"},{"id":"minecraft:shulker_shell","localizedName":"Shulker Shell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_shell"},{"id":"minecraft:shulker_spawn_egg","localizedName":"Shulker Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_spawn_egg"},{"id":"minecraft:silverfish_spawn_egg","localizedName":"Silverfish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.silverfish_spawn_egg"},{"id":"minecraft:skeleton_horse_spawn_egg","localizedName":"Skeleton Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_horse_spawn_egg"},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.skeleton_skull"},{"id":"minecraft:skeleton_spawn_egg","localizedName":"Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_spawn_egg"},{"id":"minecraft:skull_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.skull_banner_pattern"},{"id":"minecraft:slime_ball","localizedName":"Slimeball","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.slime_ball"},{"id":"minecraft:slime_block","localizedName":"Slime Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.slime_block"},{"id":"minecraft:slime_spawn_egg","localizedName":"Slime Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.slime_spawn_egg"},{"id":"minecraft:small_amethyst_bud","localizedName":"Small Amethyst Bud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.small_amethyst_bud"},{"id":"minecraft:small_dripleaf","localizedName":"Small Dripleaf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.small_dripleaf"},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smithing_table"},{"id":"minecraft:smoker","localizedName":"Smoker","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smoker"},{"id":"minecraft:smooth_basalt","localizedName":"Smooth Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_basalt"},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz"},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_slab"},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_stairs"},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone"},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_slab"},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_stairs"},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone"},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_slab"},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_stairs"},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone"},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone_slab"},{"id":"minecraft:snow","localizedName":"Snow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.snow"},{"id":"minecraft:snow_block","localizedName":"Snow Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.snow_block"},{"id":"minecraft:snowball","localizedName":"Snowball","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.snowball"},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_campfire"},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_lantern"},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_sand"},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_soil"},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_torch"},{"id":"minecraft:spawner","localizedName":"Spawner","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spawner"},{"id":"minecraft:spectral_arrow","localizedName":"Spectral Arrow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spectral_arrow"},{"id":"minecraft:spider_eye","localizedName":"Spider Eye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spider_eye"},{"id":"minecraft:spider_spawn_egg","localizedName":"Spider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spider_spawn_egg"},{"id":"minecraft:splash_potion","localizedName":"Splash Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.splash_potion.effect.water"},{"id":"minecraft:sponge","localizedName":"Sponge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sponge"},{"id":"minecraft:spore_blossom","localizedName":"Spore Blossom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spore_blossom"},{"id":"minecraft:spruce_boat","localizedName":"Spruce Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.spruce_boat"},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_button"},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_door"},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence"},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence_gate"},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_leaves"},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_log"},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_planks"},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_pressure_plate"},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_sapling"},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.spruce_sign"},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_slab"},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_stairs"},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_trapdoor"},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_wood"},{"id":"minecraft:spyglass","localizedName":"Spyglass","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.spyglass"},{"id":"minecraft:squid_spawn_egg","localizedName":"Squid Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.squid_spawn_egg"},{"id":"minecraft:stick","localizedName":"Stick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.stick"},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sticky_piston"},{"id":"minecraft:stone","localizedName":"Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone"},{"id":"minecraft:stone_axe","localizedName":"Stone Axe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_axe"},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_slab"},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_stairs"},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_wall"},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_bricks"},{"id":"minecraft:stone_button","localizedName":"Stone Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_button"},{"id":"minecraft:stone_hoe","localizedName":"Stone Hoe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_hoe"},{"id":"minecraft:stone_pickaxe","localizedName":"Stone Pickaxe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_pickaxe"},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_pressure_plate"},{"id":"minecraft:stone_shovel","localizedName":"Stone Shovel","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_shovel"},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_slab"},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_stairs"},{"id":"minecraft:stone_sword","localizedName":"Stone Sword","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_sword"},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stonecutter"},{"id":"minecraft:stray_spawn_egg","localizedName":"Stray Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.stray_spawn_egg"},{"id":"minecraft:strider_spawn_egg","localizedName":"Strider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.strider_spawn_egg"},{"id":"minecraft:string","localizedName":"String","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.string"},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_log"},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_wood"},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_log"},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_wood"},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_hyphae"},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_stem"},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_log"},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_wood"},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_log"},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_wood"},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_log"},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_wood"},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_log"},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_wood"},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_hyphae"},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_stem"},{"id":"minecraft:structure_block","localizedName":"Structure Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.structure_block"},{"id":"minecraft:structure_void","localizedName":"Structure Void","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.structure_void"},{"id":"minecraft:sugar","localizedName":"Sugar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sugar"},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sugar_cane"},{"id":"minecraft:sunflower","localizedName":"Sunflower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sunflower"},{"id":"minecraft:suspicious_stew","localizedName":"Suspicious Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.suspicious_stew"},{"id":"minecraft:sweet_berries","localizedName":"Sweet Berries","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sweet_berries"},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tall_grass"},{"id":"minecraft:target","localizedName":"Target","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.target"},{"id":"minecraft:terracotta","localizedName":"Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.terracotta"},{"id":"minecraft:tinted_glass","localizedName":"Tinted Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tinted_glass"},{"id":"minecraft:tipped_arrow","localizedName":"Arrow of Poison","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tipped_arrow.effect.poison"},{"id":"minecraft:tnt","localizedName":"TNT","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tnt"},{"id":"minecraft:tnt_minecart","localizedName":"Minecart with TNT","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.tnt_minecart"},{"id":"minecraft:torch","localizedName":"Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.torch"},{"id":"minecraft:totem_of_undying","localizedName":"Totem of Undying","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.totem_of_undying"},{"id":"minecraft:trader_llama_spawn_egg","localizedName":"Trader Llama Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.trader_llama_spawn_egg"},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.trapped_chest"},{"id":"minecraft:trident","localizedName":"Trident","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.trident"},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tripwire_hook"},{"id":"minecraft:tropical_fish","localizedName":"Tropical Fish","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish"},{"id":"minecraft:tropical_fish_bucket","localizedName":"Bucket of Tropical Fish","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.tropical_fish_bucket"},{"id":"minecraft:tropical_fish_spawn_egg","localizedName":"Tropical Fish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish_spawn_egg"},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral"},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_block"},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_fan"},{"id":"minecraft:tuff","localizedName":"Tuff","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tuff"},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.turtle_egg"},{"id":"minecraft:turtle_helmet","localizedName":"Turtle Shell","maxDamage":275,"maxStackSize":1,"unlocalizedName":"item.minecraft.turtle_helmet"},{"id":"minecraft:turtle_spawn_egg","localizedName":"Turtle Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.turtle_spawn_egg"},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.twisting_vines"},{"id":"minecraft:vex_spawn_egg","localizedName":"Vex Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.vex_spawn_egg"},{"id":"minecraft:villager_spawn_egg","localizedName":"Villager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.villager_spawn_egg"},{"id":"minecraft:vindicator_spawn_egg","localizedName":"Vindicator Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.vindicator_spawn_egg"},{"id":"minecraft:vine","localizedName":"Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.vine"},{"id":"minecraft:wandering_trader_spawn_egg","localizedName":"Wandering Trader Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wandering_trader_spawn_egg"},{"id":"minecraft:warped_button","localizedName":"Warped Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_button"},{"id":"minecraft:warped_door","localizedName":"Warped Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_door"},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence"},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence_gate"},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fungus"},{"id":"minecraft:warped_fungus_on_a_stick","localizedName":"Warped Fungus on a Stick","maxDamage":100,"maxStackSize":1,"unlocalizedName":"item.minecraft.warped_fungus_on_a_stick"},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_hyphae"},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_nylium"},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_planks"},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_pressure_plate"},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_roots"},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.warped_sign"},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_slab"},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stairs"},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stem"},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_trapdoor"},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_wart_block"},{"id":"minecraft:water_bucket","localizedName":"Water Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.water_bucket"},{"id":"minecraft:waxed_copper_block","localizedName":"Waxed Block of Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_copper_block"},{"id":"minecraft:waxed_cut_copper","localizedName":"Waxed Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper"},{"id":"minecraft:waxed_cut_copper_slab","localizedName":"Waxed Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper_slab"},{"id":"minecraft:waxed_cut_copper_stairs","localizedName":"Waxed Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper_stairs"},{"id":"minecraft:waxed_exposed_copper","localizedName":"Waxed Exposed Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_copper"},{"id":"minecraft:waxed_exposed_cut_copper","localizedName":"Waxed Exposed Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper"},{"id":"minecraft:waxed_exposed_cut_copper_slab","localizedName":"Waxed Exposed Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper_slab"},{"id":"minecraft:waxed_exposed_cut_copper_stairs","localizedName":"Waxed Exposed Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper_stairs"},{"id":"minecraft:waxed_oxidized_copper","localizedName":"Waxed Oxidized Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_copper"},{"id":"minecraft:waxed_oxidized_cut_copper","localizedName":"Waxed Oxidized Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper"},{"id":"minecraft:waxed_oxidized_cut_copper_slab","localizedName":"Waxed Oxidized Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper_slab"},{"id":"minecraft:waxed_oxidized_cut_copper_stairs","localizedName":"Waxed Oxidized Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper_stairs"},{"id":"minecraft:waxed_weathered_copper","localizedName":"Waxed Weathered Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_copper"},{"id":"minecraft:waxed_weathered_cut_copper","localizedName":"Waxed Weathered Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper"},{"id":"minecraft:waxed_weathered_cut_copper_slab","localizedName":"Waxed Weathered Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper_slab"},{"id":"minecraft:waxed_weathered_cut_copper_stairs","localizedName":"Waxed Weathered Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper_stairs"},{"id":"minecraft:weathered_copper","localizedName":"Weathered Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_copper"},{"id":"minecraft:weathered_cut_copper","localizedName":"Weathered Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper"},{"id":"minecraft:weathered_cut_copper_slab","localizedName":"Weathered Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper_slab"},{"id":"minecraft:weathered_cut_copper_stairs","localizedName":"Weathered Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper_stairs"},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weeping_vines"},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wet_sponge"},{"id":"minecraft:wheat","localizedName":"Wheat","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wheat"},{"id":"minecraft:wheat_seeds","localizedName":"Wheat Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wheat_seeds"},{"id":"minecraft:white_banner","localizedName":"White Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.white_banner"},{"id":"minecraft:white_bed","localizedName":"White Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.white_bed"},{"id":"minecraft:white_candle","localizedName":"White Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_candle"},{"id":"minecraft:white_carpet","localizedName":"White Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_carpet"},{"id":"minecraft:white_concrete","localizedName":"White Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete"},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete_powder"},{"id":"minecraft:white_dye","localizedName":"White Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.white_dye"},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_glazed_terracotta"},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.white_shulker_box"},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass"},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass_pane"},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_terracotta"},{"id":"minecraft:white_tulip","localizedName":"White Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_tulip"},{"id":"minecraft:white_wool","localizedName":"White Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_wool"},{"id":"minecraft:witch_spawn_egg","localizedName":"Witch Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.witch_spawn_egg"},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wither_rose"},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wither_skeleton_skull"},{"id":"minecraft:wither_skeleton_spawn_egg","localizedName":"Wither Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wither_skeleton_spawn_egg"},{"id":"minecraft:wolf_spawn_egg","localizedName":"Wolf Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wolf_spawn_egg"},{"id":"minecraft:wooden_axe","localizedName":"Wooden Axe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_axe"},{"id":"minecraft:wooden_hoe","localizedName":"Wooden Hoe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_hoe"},{"id":"minecraft:wooden_pickaxe","localizedName":"Wooden Pickaxe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_pickaxe"},{"id":"minecraft:wooden_shovel","localizedName":"Wooden Shovel","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_shovel"},{"id":"minecraft:wooden_sword","localizedName":"Wooden Sword","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_sword"},{"id":"minecraft:writable_book","localizedName":"Book and Quill","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.writable_book"},{"id":"minecraft:written_book","localizedName":"Written Book","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.written_book"},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.yellow_banner"},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_bed"},{"id":"minecraft:yellow_candle","localizedName":"Yellow Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_candle"},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_carpet"},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete"},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete_powder"},{"id":"minecraft:yellow_dye","localizedName":"Yellow Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.yellow_dye"},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_glazed_terracotta"},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_shulker_box"},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass"},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass_pane"},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_terracotta"},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_wool"},{"id":"minecraft:zoglin_spawn_egg","localizedName":"Zoglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zoglin_spawn_egg"},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.zombie_head"},{"id":"minecraft:zombie_horse_spawn_egg","localizedName":"Zombie Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_horse_spawn_egg"},{"id":"minecraft:zombie_spawn_egg","localizedName":"Zombie Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_spawn_egg"},{"id":"minecraft:zombie_villager_spawn_egg","localizedName":"Zombie Villager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_villager_spawn_egg"},{"id":"minecraft:zombified_piglin_spawn_egg","localizedName":"Zombified Piglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombified_piglin_spawn_egg"}] diff --git a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.119.json b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.119.json deleted file mode 100644 index 4166656e3..000000000 --- a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.119.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":"minecraft:acacia_boat","localizedName":"Acacia Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.acacia_boat"},{"id":"minecraft:acacia_button","localizedName":"Acacia Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_button"},{"id":"minecraft:acacia_chest_boat","localizedName":"Acacia Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.acacia_chest_boat"},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_door"},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence"},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence_gate"},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_leaves"},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_log"},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_planks"},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_pressure_plate"},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_sapling"},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.acacia_sign"},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_slab"},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_stairs"},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_trapdoor"},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_wood"},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.activator_rail"},{"id":"minecraft:air","localizedName":"Air","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.air"},{"id":"minecraft:allay_spawn_egg","localizedName":"Allay Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.allay_spawn_egg"},{"id":"minecraft:allium","localizedName":"Allium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.allium"},{"id":"minecraft:amethyst_block","localizedName":"Block of Amethyst","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.amethyst_block"},{"id":"minecraft:amethyst_cluster","localizedName":"Amethyst Cluster","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.amethyst_cluster"},{"id":"minecraft:amethyst_shard","localizedName":"Amethyst Shard","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.amethyst_shard"},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ancient_debris"},{"id":"minecraft:andesite","localizedName":"Andesite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite"},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_slab"},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_stairs"},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_wall"},{"id":"minecraft:anvil","localizedName":"Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.anvil"},{"id":"minecraft:apple","localizedName":"Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.apple"},{"id":"minecraft:armor_stand","localizedName":"Armor Stand","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.armor_stand"},{"id":"minecraft:arrow","localizedName":"Arrow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.arrow"},{"id":"minecraft:axolotl_bucket","localizedName":"Bucket of Axolotl","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.axolotl_bucket"},{"id":"minecraft:axolotl_spawn_egg","localizedName":"Axolotl Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.axolotl_spawn_egg"},{"id":"minecraft:azalea","localizedName":"Azalea","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.azalea"},{"id":"minecraft:azalea_leaves","localizedName":"Azalea Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.azalea_leaves"},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.azure_bluet"},{"id":"minecraft:baked_potato","localizedName":"Baked Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.baked_potato"},{"id":"minecraft:bamboo","localizedName":"Bamboo","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo"},{"id":"minecraft:barrel","localizedName":"Barrel","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.barrel"},{"id":"minecraft:barrier","localizedName":"Barrier","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.barrier"},{"id":"minecraft:basalt","localizedName":"Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.basalt"},{"id":"minecraft:bat_spawn_egg","localizedName":"Bat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bat_spawn_egg"},{"id":"minecraft:beacon","localizedName":"Beacon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.beacon"},{"id":"minecraft:bedrock","localizedName":"Bedrock","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bedrock"},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bee_nest"},{"id":"minecraft:bee_spawn_egg","localizedName":"Bee Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bee_spawn_egg"},{"id":"minecraft:beef","localizedName":"Raw Beef","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beef"},{"id":"minecraft:beehive","localizedName":"Beehive","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.beehive"},{"id":"minecraft:beetroot","localizedName":"Beetroot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot"},{"id":"minecraft:beetroot_seeds","localizedName":"Beetroot Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot_seeds"},{"id":"minecraft:beetroot_soup","localizedName":"Beetroot Soup","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.beetroot_soup"},{"id":"minecraft:bell","localizedName":"Bell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bell"},{"id":"minecraft:big_dripleaf","localizedName":"Big Dripleaf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.big_dripleaf"},{"id":"minecraft:birch_boat","localizedName":"Birch Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.birch_boat"},{"id":"minecraft:birch_button","localizedName":"Birch Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_button"},{"id":"minecraft:birch_chest_boat","localizedName":"Birch Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.birch_chest_boat"},{"id":"minecraft:birch_door","localizedName":"Birch Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_door"},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence"},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence_gate"},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_leaves"},{"id":"minecraft:birch_log","localizedName":"Birch Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_log"},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_planks"},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_pressure_plate"},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_sapling"},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.birch_sign"},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_slab"},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_stairs"},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_trapdoor"},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.birch_wood"},{"id":"minecraft:black_banner","localizedName":"Black Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.black_banner"},{"id":"minecraft:black_bed","localizedName":"Black Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.black_bed"},{"id":"minecraft:black_candle","localizedName":"Black Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_candle"},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_carpet"},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete"},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete_powder"},{"id":"minecraft:black_dye","localizedName":"Black Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.black_dye"},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_glazed_terracotta"},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.black_shulker_box"},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass"},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass_pane"},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_terracotta"},{"id":"minecraft:black_wool","localizedName":"Black Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.black_wool"},{"id":"minecraft:blackstone","localizedName":"Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone"},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_slab"},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_stairs"},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_wall"},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blast_furnace"},{"id":"minecraft:blaze_powder","localizedName":"Blaze Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_powder"},{"id":"minecraft:blaze_rod","localizedName":"Blaze Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_rod"},{"id":"minecraft:blaze_spawn_egg","localizedName":"Blaze Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_spawn_egg"},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.blue_banner"},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.blue_bed"},{"id":"minecraft:blue_candle","localizedName":"Blue Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_candle"},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_carpet"},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete"},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete_powder"},{"id":"minecraft:blue_dye","localizedName":"Blue Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.blue_dye"},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_glazed_terracotta"},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_ice"},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_orchid"},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.blue_shulker_box"},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass"},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass_pane"},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_terracotta"},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.blue_wool"},{"id":"minecraft:bone","localizedName":"Bone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bone"},{"id":"minecraft:bone_block","localizedName":"Bone Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bone_block"},{"id":"minecraft:bone_meal","localizedName":"Bone Meal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bone_meal"},{"id":"minecraft:book","localizedName":"Book","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.book"},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bookshelf"},{"id":"minecraft:bow","localizedName":"Bow","maxDamage":384,"maxStackSize":1,"unlocalizedName":"item.minecraft.bow"},{"id":"minecraft:bowl","localizedName":"Bowl","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bowl"},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral"},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_block"},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_fan"},{"id":"minecraft:bread","localizedName":"Bread","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.bread"},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brewing_stand"},{"id":"minecraft:brick","localizedName":"Brick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.brick"},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_slab"},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_stairs"},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brick_wall"},{"id":"minecraft:bricks","localizedName":"Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bricks"},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.brown_banner"},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.brown_bed"},{"id":"minecraft:brown_candle","localizedName":"Brown Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_candle"},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_carpet"},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete"},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete_powder"},{"id":"minecraft:brown_dye","localizedName":"Brown Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.brown_dye"},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_glazed_terracotta"},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom"},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom_block"},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.brown_shulker_box"},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass"},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass_pane"},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_terracotta"},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.brown_wool"},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral"},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_block"},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_fan"},{"id":"minecraft:bucket","localizedName":"Bucket","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.bucket"},{"id":"minecraft:budding_amethyst","localizedName":"Budding Amethyst","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.budding_amethyst"},{"id":"minecraft:bundle","localizedName":"Bundle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.bundle"},{"id":"minecraft:cactus","localizedName":"Cactus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cactus"},{"id":"minecraft:cake","localizedName":"Cake","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cake"},{"id":"minecraft:calcite","localizedName":"Calcite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.calcite"},{"id":"minecraft:campfire","localizedName":"Campfire","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.campfire"},{"id":"minecraft:candle","localizedName":"Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.candle"},{"id":"minecraft:carrot","localizedName":"Carrot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.carrot"},{"id":"minecraft:carrot_on_a_stick","localizedName":"Carrot on a Stick","maxDamage":25,"maxStackSize":1,"unlocalizedName":"item.minecraft.carrot_on_a_stick"},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cartography_table"},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.carved_pumpkin"},{"id":"minecraft:cat_spawn_egg","localizedName":"Cat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cat_spawn_egg"},{"id":"minecraft:cauldron","localizedName":"Cauldron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cauldron"},{"id":"minecraft:cave_spider_spawn_egg","localizedName":"Cave Spider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cave_spider_spawn_egg"},{"id":"minecraft:chain","localizedName":"Chain","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chain"},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chain_command_block"},{"id":"minecraft:chainmail_boots","localizedName":"Chainmail Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_boots"},{"id":"minecraft:chainmail_chestplate","localizedName":"Chainmail Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_chestplate"},{"id":"minecraft:chainmail_helmet","localizedName":"Chainmail Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_helmet"},{"id":"minecraft:chainmail_leggings","localizedName":"Chainmail Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_leggings"},{"id":"minecraft:charcoal","localizedName":"Charcoal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.charcoal"},{"id":"minecraft:chest","localizedName":"Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chest"},{"id":"minecraft:chest_minecart","localizedName":"Minecart with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.chest_minecart"},{"id":"minecraft:chicken","localizedName":"Raw Chicken","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chicken"},{"id":"minecraft:chicken_spawn_egg","localizedName":"Chicken Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chicken_spawn_egg"},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chipped_anvil"},{"id":"minecraft:chiseled_deepslate","localizedName":"Chiseled Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_deepslate"},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_nether_bricks"},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_polished_blackstone"},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_quartz_block"},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_red_sandstone"},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_sandstone"},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_stone_bricks"},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_flower"},{"id":"minecraft:chorus_fruit","localizedName":"Chorus Fruit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.chorus_fruit"},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_plant"},{"id":"minecraft:clay","localizedName":"Clay","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.clay"},{"id":"minecraft:clay_ball","localizedName":"Clay Ball","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.clay_ball"},{"id":"minecraft:clock","localizedName":"Clock","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.clock"},{"id":"minecraft:coal","localizedName":"Coal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.coal"},{"id":"minecraft:coal_block","localizedName":"Block of Coal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coal_block"},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coal_ore"},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.coarse_dirt"},{"id":"minecraft:cobbled_deepslate","localizedName":"Cobbled Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate"},{"id":"minecraft:cobbled_deepslate_slab","localizedName":"Cobbled Deepslate Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_slab"},{"id":"minecraft:cobbled_deepslate_stairs","localizedName":"Cobbled Deepslate Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_stairs"},{"id":"minecraft:cobbled_deepslate_wall","localizedName":"Cobbled Deepslate Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_wall"},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone"},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_slab"},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_stairs"},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_wall"},{"id":"minecraft:cobweb","localizedName":"Cobweb","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cobweb"},{"id":"minecraft:cocoa_beans","localizedName":"Cocoa Beans","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cocoa_beans"},{"id":"minecraft:cod","localizedName":"Raw Cod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cod"},{"id":"minecraft:cod_bucket","localizedName":"Bucket of Cod","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.cod_bucket"},{"id":"minecraft:cod_spawn_egg","localizedName":"Cod Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cod_spawn_egg"},{"id":"minecraft:command_block","localizedName":"Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.command_block"},{"id":"minecraft:command_block_minecart","localizedName":"Minecart with Command Block","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.command_block_minecart"},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.comparator"},{"id":"minecraft:compass","localizedName":"Compass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.compass"},{"id":"minecraft:composter","localizedName":"Composter","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.composter"},{"id":"minecraft:conduit","localizedName":"Conduit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.conduit"},{"id":"minecraft:cooked_beef","localizedName":"Steak","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_beef"},{"id":"minecraft:cooked_chicken","localizedName":"Cooked Chicken","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_chicken"},{"id":"minecraft:cooked_cod","localizedName":"Cooked Cod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_cod"},{"id":"minecraft:cooked_mutton","localizedName":"Cooked Mutton","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_mutton"},{"id":"minecraft:cooked_porkchop","localizedName":"Cooked Porkchop","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_porkchop"},{"id":"minecraft:cooked_rabbit","localizedName":"Cooked Rabbit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_rabbit"},{"id":"minecraft:cooked_salmon","localizedName":"Cooked Salmon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_salmon"},{"id":"minecraft:cookie","localizedName":"Cookie","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cookie"},{"id":"minecraft:copper_block","localizedName":"Block of Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.copper_block"},{"id":"minecraft:copper_ingot","localizedName":"Copper Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.copper_ingot"},{"id":"minecraft:copper_ore","localizedName":"Copper Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.copper_ore"},{"id":"minecraft:cornflower","localizedName":"Cornflower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cornflower"},{"id":"minecraft:cow_spawn_egg","localizedName":"Cow Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cow_spawn_egg"},{"id":"minecraft:cracked_deepslate_bricks","localizedName":"Cracked Deepslate Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_deepslate_bricks"},{"id":"minecraft:cracked_deepslate_tiles","localizedName":"Cracked Deepslate Tiles","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_deepslate_tiles"},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_nether_bricks"},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_polished_blackstone_bricks"},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_stone_bricks"},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crafting_table"},{"id":"minecraft:creeper_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.creeper_banner_pattern"},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.creeper_head"},{"id":"minecraft:creeper_spawn_egg","localizedName":"Creeper Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.creeper_spawn_egg"},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_button"},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_door"},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence"},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence_gate"},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fungus"},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_hyphae"},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_nylium"},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_planks"},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_pressure_plate"},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_roots"},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.crimson_sign"},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_slab"},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stairs"},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stem"},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_trapdoor"},{"id":"minecraft:crossbow","localizedName":"Crossbow","maxDamage":465,"maxStackSize":1,"unlocalizedName":"item.minecraft.crossbow"},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.crying_obsidian"},{"id":"minecraft:cut_copper","localizedName":"Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper"},{"id":"minecraft:cut_copper_slab","localizedName":"Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper_slab"},{"id":"minecraft:cut_copper_stairs","localizedName":"Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper_stairs"},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone"},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone_slab"},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone"},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone_slab"},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.cyan_banner"},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_bed"},{"id":"minecraft:cyan_candle","localizedName":"Cyan Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_candle"},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_carpet"},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete"},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete_powder"},{"id":"minecraft:cyan_dye","localizedName":"Cyan Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.cyan_dye"},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_glazed_terracotta"},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_shulker_box"},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass"},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass_pane"},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_terracotta"},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_wool"},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.damaged_anvil"},{"id":"minecraft:dandelion","localizedName":"Dandelion","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dandelion"},{"id":"minecraft:dark_oak_boat","localizedName":"Dark Oak Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.dark_oak_boat"},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_button"},{"id":"minecraft:dark_oak_chest_boat","localizedName":"Dark Oak Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.dark_oak_chest_boat"},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_door"},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence"},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence_gate"},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_leaves"},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_log"},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_planks"},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_pressure_plate"},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_sapling"},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.dark_oak_sign"},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_slab"},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_stairs"},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_trapdoor"},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_wood"},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine"},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_slab"},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_stairs"},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.daylight_detector"},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral"},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_block"},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_fan"},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral"},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_block"},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_fan"},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bush"},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral"},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_block"},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_fan"},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral"},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_block"},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_fan"},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral"},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_block"},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_fan"},{"id":"minecraft:debug_stick","localizedName":"Debug Stick","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.debug_stick"},{"id":"minecraft:deepslate","localizedName":"Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate"},{"id":"minecraft:deepslate_brick_slab","localizedName":"Deepslate Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_slab"},{"id":"minecraft:deepslate_brick_stairs","localizedName":"Deepslate Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_stairs"},{"id":"minecraft:deepslate_brick_wall","localizedName":"Deepslate Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_wall"},{"id":"minecraft:deepslate_bricks","localizedName":"Deepslate Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_bricks"},{"id":"minecraft:deepslate_coal_ore","localizedName":"Deepslate Coal Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_coal_ore"},{"id":"minecraft:deepslate_copper_ore","localizedName":"Deepslate Copper Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_copper_ore"},{"id":"minecraft:deepslate_diamond_ore","localizedName":"Deepslate Diamond Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_diamond_ore"},{"id":"minecraft:deepslate_emerald_ore","localizedName":"Deepslate Emerald Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_emerald_ore"},{"id":"minecraft:deepslate_gold_ore","localizedName":"Deepslate Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_gold_ore"},{"id":"minecraft:deepslate_iron_ore","localizedName":"Deepslate Iron Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_iron_ore"},{"id":"minecraft:deepslate_lapis_ore","localizedName":"Deepslate Lapis Lazuli Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_lapis_ore"},{"id":"minecraft:deepslate_redstone_ore","localizedName":"Deepslate Redstone Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_redstone_ore"},{"id":"minecraft:deepslate_tile_slab","localizedName":"Deepslate Tile Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_slab"},{"id":"minecraft:deepslate_tile_stairs","localizedName":"Deepslate Tile Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_stairs"},{"id":"minecraft:deepslate_tile_wall","localizedName":"Deepslate Tile Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_wall"},{"id":"minecraft:deepslate_tiles","localizedName":"Deepslate Tiles","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tiles"},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.detector_rail"},{"id":"minecraft:diamond","localizedName":"Diamond","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.diamond"},{"id":"minecraft:diamond_axe","localizedName":"Diamond Axe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_axe"},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_block"},{"id":"minecraft:diamond_boots","localizedName":"Diamond Boots","maxDamage":429,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_boots"},{"id":"minecraft:diamond_chestplate","localizedName":"Diamond Chestplate","maxDamage":528,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_chestplate"},{"id":"minecraft:diamond_helmet","localizedName":"Diamond Helmet","maxDamage":363,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_helmet"},{"id":"minecraft:diamond_hoe","localizedName":"Diamond Hoe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_hoe"},{"id":"minecraft:diamond_horse_armor","localizedName":"Diamond Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_horse_armor"},{"id":"minecraft:diamond_leggings","localizedName":"Diamond Leggings","maxDamage":495,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_leggings"},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_ore"},{"id":"minecraft:diamond_pickaxe","localizedName":"Diamond Pickaxe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_pickaxe"},{"id":"minecraft:diamond_shovel","localizedName":"Diamond Shovel","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_shovel"},{"id":"minecraft:diamond_sword","localizedName":"Diamond Sword","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_sword"},{"id":"minecraft:diorite","localizedName":"Diorite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite"},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_slab"},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_stairs"},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_wall"},{"id":"minecraft:dirt","localizedName":"Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dirt"},{"id":"minecraft:dirt_path","localizedName":"Dirt Path","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dirt_path"},{"id":"minecraft:disc_fragment_5","localizedName":"Disc Fragment","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.disc_fragment_5"},{"id":"minecraft:dispenser","localizedName":"Dispenser","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dispenser"},{"id":"minecraft:dolphin_spawn_egg","localizedName":"Dolphin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dolphin_spawn_egg"},{"id":"minecraft:donkey_spawn_egg","localizedName":"Donkey Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.donkey_spawn_egg"},{"id":"minecraft:dragon_breath","localizedName":"Dragon\u0027s Breath","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dragon_breath"},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_egg"},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_head"},{"id":"minecraft:dried_kelp","localizedName":"Dried Kelp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.dried_kelp"},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dried_kelp_block"},{"id":"minecraft:dripstone_block","localizedName":"Dripstone Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dripstone_block"},{"id":"minecraft:dropper","localizedName":"Dropper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.dropper"},{"id":"minecraft:drowned_spawn_egg","localizedName":"Drowned Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.drowned_spawn_egg"},{"id":"minecraft:echo_shard","localizedName":"Echo Shard","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.echo_shard"},{"id":"minecraft:egg","localizedName":"Egg","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.egg"},{"id":"minecraft:elder_guardian_spawn_egg","localizedName":"Elder Guardian Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.elder_guardian_spawn_egg"},{"id":"minecraft:elytra","localizedName":"Elytra","maxDamage":432,"maxStackSize":1,"unlocalizedName":"item.minecraft.elytra"},{"id":"minecraft:emerald","localizedName":"Emerald","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.emerald"},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_block"},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_ore"},{"id":"minecraft:enchanted_book","localizedName":"Enchanted Book","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.enchanted_book"},{"id":"minecraft:enchanted_golden_apple","localizedName":"Enchanted Golden Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.enchanted_golden_apple"},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.enchanting_table"},{"id":"minecraft:end_crystal","localizedName":"End Crystal","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.end_crystal"},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_portal_frame"},{"id":"minecraft:end_rod","localizedName":"End Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_rod"},{"id":"minecraft:end_stone","localizedName":"End Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone"},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_slab"},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_stairs"},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_wall"},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_bricks"},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ender_chest"},{"id":"minecraft:ender_eye","localizedName":"Eye of Ender","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ender_eye"},{"id":"minecraft:ender_pearl","localizedName":"Ender Pearl","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.ender_pearl"},{"id":"minecraft:enderman_spawn_egg","localizedName":"Enderman Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.enderman_spawn_egg"},{"id":"minecraft:endermite_spawn_egg","localizedName":"Endermite Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.endermite_spawn_egg"},{"id":"minecraft:evoker_spawn_egg","localizedName":"Evoker Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.evoker_spawn_egg"},{"id":"minecraft:experience_bottle","localizedName":"Bottle o\u0027 Enchanting","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.experience_bottle"},{"id":"minecraft:exposed_copper","localizedName":"Exposed Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_copper"},{"id":"minecraft:exposed_cut_copper","localizedName":"Exposed Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper"},{"id":"minecraft:exposed_cut_copper_slab","localizedName":"Exposed Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper_slab"},{"id":"minecraft:exposed_cut_copper_stairs","localizedName":"Exposed Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper_stairs"},{"id":"minecraft:farmland","localizedName":"Farmland","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.farmland"},{"id":"minecraft:feather","localizedName":"Feather","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.feather"},{"id":"minecraft:fermented_spider_eye","localizedName":"Fermented Spider Eye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fermented_spider_eye"},{"id":"minecraft:fern","localizedName":"Fern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fern"},{"id":"minecraft:filled_map","localizedName":"Map","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.filled_map"},{"id":"minecraft:fire_charge","localizedName":"Fire Charge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fire_charge"},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral"},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_block"},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_fan"},{"id":"minecraft:firework_rocket","localizedName":"Firework Rocket","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.firework_rocket"},{"id":"minecraft:firework_star","localizedName":"Firework Star","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.firework_star"},{"id":"minecraft:fishing_rod","localizedName":"Fishing Rod","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.fishing_rod"},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.fletching_table"},{"id":"minecraft:flint","localizedName":"Flint","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.flint"},{"id":"minecraft:flint_and_steel","localizedName":"Flint and Steel","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.flint_and_steel"},{"id":"minecraft:flower_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.flower_banner_pattern"},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.flower_pot"},{"id":"minecraft:flowering_azalea","localizedName":"Flowering Azalea","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.flowering_azalea"},{"id":"minecraft:flowering_azalea_leaves","localizedName":"Flowering Azalea Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.flowering_azalea_leaves"},{"id":"minecraft:fox_spawn_egg","localizedName":"Fox Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.fox_spawn_egg"},{"id":"minecraft:frog_spawn_egg","localizedName":"Frog Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.frog_spawn_egg"},{"id":"minecraft:frogspawn","localizedName":"Frogspawn","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.frogspawn"},{"id":"minecraft:furnace","localizedName":"Furnace","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.furnace"},{"id":"minecraft:furnace_minecart","localizedName":"Minecart with Furnace","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.furnace_minecart"},{"id":"minecraft:ghast_spawn_egg","localizedName":"Ghast Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_spawn_egg"},{"id":"minecraft:ghast_tear","localizedName":"Ghast Tear","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_tear"},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gilded_blackstone"},{"id":"minecraft:glass","localizedName":"Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glass"},{"id":"minecraft:glass_bottle","localizedName":"Glass Bottle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glass_bottle"},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glass_pane"},{"id":"minecraft:glistering_melon_slice","localizedName":"Glistering Melon Slice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glistering_melon_slice"},{"id":"minecraft:globe_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.globe_banner_pattern"},{"id":"minecraft:glow_berries","localizedName":"Glow Berries","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_berries"},{"id":"minecraft:glow_ink_sac","localizedName":"Glow Ink Sac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_ink_sac"},{"id":"minecraft:glow_item_frame","localizedName":"Glow Item Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_item_frame"},{"id":"minecraft:glow_lichen","localizedName":"Glow Lichen","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glow_lichen"},{"id":"minecraft:glow_squid_spawn_egg","localizedName":"Glow Squid Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glow_squid_spawn_egg"},{"id":"minecraft:glowstone","localizedName":"Glowstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.glowstone"},{"id":"minecraft:glowstone_dust","localizedName":"Glowstone Dust","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.glowstone_dust"},{"id":"minecraft:goat_horn","localizedName":"Goat Horn","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.goat_horn"},{"id":"minecraft:goat_spawn_egg","localizedName":"Goat Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.goat_spawn_egg"},{"id":"minecraft:gold_block","localizedName":"Block of Gold","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gold_block"},{"id":"minecraft:gold_ingot","localizedName":"Gold Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gold_ingot"},{"id":"minecraft:gold_nugget","localizedName":"Gold Nugget","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gold_nugget"},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gold_ore"},{"id":"minecraft:golden_apple","localizedName":"Golden Apple","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.golden_apple"},{"id":"minecraft:golden_axe","localizedName":"Golden Axe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_axe"},{"id":"minecraft:golden_boots","localizedName":"Golden Boots","maxDamage":91,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_boots"},{"id":"minecraft:golden_carrot","localizedName":"Golden Carrot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.golden_carrot"},{"id":"minecraft:golden_chestplate","localizedName":"Golden Chestplate","maxDamage":112,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_chestplate"},{"id":"minecraft:golden_helmet","localizedName":"Golden Helmet","maxDamage":77,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_helmet"},{"id":"minecraft:golden_hoe","localizedName":"Golden Hoe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_hoe"},{"id":"minecraft:golden_horse_armor","localizedName":"Golden Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_horse_armor"},{"id":"minecraft:golden_leggings","localizedName":"Golden Leggings","maxDamage":105,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_leggings"},{"id":"minecraft:golden_pickaxe","localizedName":"Golden Pickaxe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_pickaxe"},{"id":"minecraft:golden_shovel","localizedName":"Golden Shovel","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_shovel"},{"id":"minecraft:golden_sword","localizedName":"Golden Sword","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_sword"},{"id":"minecraft:granite","localizedName":"Granite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite"},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_slab"},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_stairs"},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.granite_wall"},{"id":"minecraft:grass","localizedName":"Grass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grass"},{"id":"minecraft:grass_block","localizedName":"Grass Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grass_block"},{"id":"minecraft:gravel","localizedName":"Gravel","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gravel"},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.gray_banner"},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.gray_bed"},{"id":"minecraft:gray_candle","localizedName":"Gray Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_candle"},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_carpet"},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete"},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete_powder"},{"id":"minecraft:gray_dye","localizedName":"Gray Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gray_dye"},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_glazed_terracotta"},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.gray_shulker_box"},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass"},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass_pane"},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_terracotta"},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.gray_wool"},{"id":"minecraft:green_banner","localizedName":"Green Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.green_banner"},{"id":"minecraft:green_bed","localizedName":"Green Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.green_bed"},{"id":"minecraft:green_candle","localizedName":"Green Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_candle"},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_carpet"},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete"},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete_powder"},{"id":"minecraft:green_dye","localizedName":"Green Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.green_dye"},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_glazed_terracotta"},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.green_shulker_box"},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass"},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass_pane"},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_terracotta"},{"id":"minecraft:green_wool","localizedName":"Green Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.green_wool"},{"id":"minecraft:grindstone","localizedName":"Grindstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.grindstone"},{"id":"minecraft:guardian_spawn_egg","localizedName":"Guardian Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.guardian_spawn_egg"},{"id":"minecraft:gunpowder","localizedName":"Gunpowder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.gunpowder"},{"id":"minecraft:hanging_roots","localizedName":"Hanging Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hanging_roots"},{"id":"minecraft:hay_block","localizedName":"Hay Bale","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hay_block"},{"id":"minecraft:heart_of_the_sea","localizedName":"Heart of the Sea","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.heart_of_the_sea"},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.heavy_weighted_pressure_plate"},{"id":"minecraft:hoglin_spawn_egg","localizedName":"Hoglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.hoglin_spawn_egg"},{"id":"minecraft:honey_block","localizedName":"Honey Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.honey_block"},{"id":"minecraft:honey_bottle","localizedName":"Honey Bottle","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.honey_bottle"},{"id":"minecraft:honeycomb","localizedName":"Honeycomb","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.honeycomb"},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.honeycomb_block"},{"id":"minecraft:hopper","localizedName":"Hopper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.hopper"},{"id":"minecraft:hopper_minecart","localizedName":"Minecart with Hopper","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.hopper_minecart"},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral"},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_block"},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_fan"},{"id":"minecraft:horse_spawn_egg","localizedName":"Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.horse_spawn_egg"},{"id":"minecraft:husk_spawn_egg","localizedName":"Husk Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.husk_spawn_egg"},{"id":"minecraft:ice","localizedName":"Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ice"},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_chiseled_stone_bricks"},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cobblestone"},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cracked_stone_bricks"},{"id":"minecraft:infested_deepslate","localizedName":"Infested Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_deepslate"},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_mossy_stone_bricks"},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone"},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone_bricks"},{"id":"minecraft:ink_sac","localizedName":"Ink Sac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ink_sac"},{"id":"minecraft:iron_axe","localizedName":"Iron Axe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_axe"},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_bars"},{"id":"minecraft:iron_block","localizedName":"Block of Iron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_block"},{"id":"minecraft:iron_boots","localizedName":"Iron Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_boots"},{"id":"minecraft:iron_chestplate","localizedName":"Iron Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_chestplate"},{"id":"minecraft:iron_door","localizedName":"Iron Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_door"},{"id":"minecraft:iron_helmet","localizedName":"Iron Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_helmet"},{"id":"minecraft:iron_hoe","localizedName":"Iron Hoe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_hoe"},{"id":"minecraft:iron_horse_armor","localizedName":"Iron Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_horse_armor"},{"id":"minecraft:iron_ingot","localizedName":"Iron Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.iron_ingot"},{"id":"minecraft:iron_leggings","localizedName":"Iron Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_leggings"},{"id":"minecraft:iron_nugget","localizedName":"Iron Nugget","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.iron_nugget"},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_ore"},{"id":"minecraft:iron_pickaxe","localizedName":"Iron Pickaxe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_pickaxe"},{"id":"minecraft:iron_shovel","localizedName":"Iron Shovel","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_shovel"},{"id":"minecraft:iron_sword","localizedName":"Iron Sword","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_sword"},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.iron_trapdoor"},{"id":"minecraft:item_frame","localizedName":"Item Frame","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.item_frame"},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o\u0027Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jack_o_lantern"},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jigsaw"},{"id":"minecraft:jukebox","localizedName":"Jukebox","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jukebox"},{"id":"minecraft:jungle_boat","localizedName":"Jungle Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.jungle_boat"},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_button"},{"id":"minecraft:jungle_chest_boat","localizedName":"Jungle Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.jungle_chest_boat"},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_door"},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence"},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence_gate"},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_leaves"},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_log"},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_planks"},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_pressure_plate"},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_sapling"},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.jungle_sign"},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_slab"},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_stairs"},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_trapdoor"},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_wood"},{"id":"minecraft:kelp","localizedName":"Kelp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.kelp"},{"id":"minecraft:knowledge_book","localizedName":"Knowledge Book","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.knowledge_book"},{"id":"minecraft:ladder","localizedName":"Ladder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ladder"},{"id":"minecraft:lantern","localizedName":"Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lantern"},{"id":"minecraft:lapis_block","localizedName":"Block of Lapis Lazuli","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_block"},{"id":"minecraft:lapis_lazuli","localizedName":"Lapis Lazuli","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lapis_lazuli"},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_ore"},{"id":"minecraft:large_amethyst_bud","localizedName":"Large Amethyst Bud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.large_amethyst_bud"},{"id":"minecraft:large_fern","localizedName":"Large Fern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.large_fern"},{"id":"minecraft:lava_bucket","localizedName":"Lava Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.lava_bucket"},{"id":"minecraft:lead","localizedName":"Lead","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lead"},{"id":"minecraft:leather","localizedName":"Leather","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.leather"},{"id":"minecraft:leather_boots","localizedName":"Leather Boots","maxDamage":65,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_boots"},{"id":"minecraft:leather_chestplate","localizedName":"Leather Tunic","maxDamage":80,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_chestplate"},{"id":"minecraft:leather_helmet","localizedName":"Leather Cap","maxDamage":55,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_helmet"},{"id":"minecraft:leather_horse_armor","localizedName":"Leather Horse Armor","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_horse_armor"},{"id":"minecraft:leather_leggings","localizedName":"Leather Pants","maxDamage":75,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_leggings"},{"id":"minecraft:lectern","localizedName":"Lectern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lectern"},{"id":"minecraft:lever","localizedName":"Lever","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lever"},{"id":"minecraft:light","localizedName":"Light","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light"},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.light_blue_banner"},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_bed"},{"id":"minecraft:light_blue_candle","localizedName":"Light Blue Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_candle"},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_carpet"},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete"},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete_powder"},{"id":"minecraft:light_blue_dye","localizedName":"Light Blue Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.light_blue_dye"},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_glazed_terracotta"},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_shulker_box"},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass"},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass_pane"},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_terracotta"},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_wool"},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.light_gray_banner"},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_bed"},{"id":"minecraft:light_gray_candle","localizedName":"Light Gray Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_candle"},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_carpet"},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete"},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete_powder"},{"id":"minecraft:light_gray_dye","localizedName":"Light Gray Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.light_gray_dye"},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_glazed_terracotta"},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_shulker_box"},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass"},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass_pane"},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_terracotta"},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_wool"},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.light_weighted_pressure_plate"},{"id":"minecraft:lightning_rod","localizedName":"Lightning Rod","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lightning_rod"},{"id":"minecraft:lilac","localizedName":"Lilac","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lilac"},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lily_of_the_valley"},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lily_pad"},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.lime_banner"},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.lime_bed"},{"id":"minecraft:lime_candle","localizedName":"Lime Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_candle"},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_carpet"},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete"},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete_powder"},{"id":"minecraft:lime_dye","localizedName":"Lime Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.lime_dye"},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_glazed_terracotta"},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.lime_shulker_box"},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass"},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass_pane"},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_terracotta"},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lime_wool"},{"id":"minecraft:lingering_potion","localizedName":"Lingering Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.lingering_potion.effect.water"},{"id":"minecraft:llama_spawn_egg","localizedName":"Llama Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.llama_spawn_egg"},{"id":"minecraft:lodestone","localizedName":"Lodestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.lodestone"},{"id":"minecraft:loom","localizedName":"Loom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.loom"},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.magenta_banner"},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_bed"},{"id":"minecraft:magenta_candle","localizedName":"Magenta Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_candle"},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_carpet"},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete"},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete_powder"},{"id":"minecraft:magenta_dye","localizedName":"Magenta Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magenta_dye"},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_glazed_terracotta"},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_shulker_box"},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass"},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass_pane"},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_terracotta"},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_wool"},{"id":"minecraft:magma_block","localizedName":"Magma Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.magma_block"},{"id":"minecraft:magma_cream","localizedName":"Magma Cream","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cream"},{"id":"minecraft:magma_cube_spawn_egg","localizedName":"Magma Cube Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cube_spawn_egg"},{"id":"minecraft:mangrove_boat","localizedName":"Mangrove Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mangrove_boat"},{"id":"minecraft:mangrove_button","localizedName":"Mangrove Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_button"},{"id":"minecraft:mangrove_chest_boat","localizedName":"Mangrove Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mangrove_chest_boat"},{"id":"minecraft:mangrove_door","localizedName":"Mangrove Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_door"},{"id":"minecraft:mangrove_fence","localizedName":"Mangrove Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_fence"},{"id":"minecraft:mangrove_fence_gate","localizedName":"Mangrove Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_fence_gate"},{"id":"minecraft:mangrove_leaves","localizedName":"Mangrove Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_leaves"},{"id":"minecraft:mangrove_log","localizedName":"Mangrove Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_log"},{"id":"minecraft:mangrove_planks","localizedName":"Mangrove Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_planks"},{"id":"minecraft:mangrove_pressure_plate","localizedName":"Mangrove Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_pressure_plate"},{"id":"minecraft:mangrove_propagule","localizedName":"Mangrove Propagule","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_propagule"},{"id":"minecraft:mangrove_roots","localizedName":"Mangrove Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_roots"},{"id":"minecraft:mangrove_sign","localizedName":"Mangrove Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.mangrove_sign"},{"id":"minecraft:mangrove_slab","localizedName":"Mangrove Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_slab"},{"id":"minecraft:mangrove_stairs","localizedName":"Mangrove Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_stairs"},{"id":"minecraft:mangrove_trapdoor","localizedName":"Mangrove Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_trapdoor"},{"id":"minecraft:mangrove_wood","localizedName":"Mangrove Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_wood"},{"id":"minecraft:map","localizedName":"Empty Map","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.map"},{"id":"minecraft:medium_amethyst_bud","localizedName":"Medium Amethyst Bud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.medium_amethyst_bud"},{"id":"minecraft:melon","localizedName":"Melon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.melon"},{"id":"minecraft:melon_seeds","localizedName":"Melon Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.melon_seeds"},{"id":"minecraft:melon_slice","localizedName":"Melon Slice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.melon_slice"},{"id":"minecraft:milk_bucket","localizedName":"Milk Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.milk_bucket"},{"id":"minecraft:minecart","localizedName":"Minecart","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.minecart"},{"id":"minecraft:mojang_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mojang_banner_pattern"},{"id":"minecraft:mooshroom_spawn_egg","localizedName":"Mooshroom Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mooshroom_spawn_egg"},{"id":"minecraft:moss_block","localizedName":"Moss Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.moss_block"},{"id":"minecraft:moss_carpet","localizedName":"Moss Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.moss_carpet"},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone"},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_slab"},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_stairs"},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_wall"},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_slab"},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_stairs"},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_wall"},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_bricks"},{"id":"minecraft:mud","localizedName":"Mud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mud"},{"id":"minecraft:mud_brick_slab","localizedName":"Mud Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mud_brick_slab"},{"id":"minecraft:mud_brick_stairs","localizedName":"Mud Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mud_brick_stairs"},{"id":"minecraft:mud_brick_wall","localizedName":"Mud Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mud_brick_wall"},{"id":"minecraft:mud_bricks","localizedName":"Mud Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mud_bricks"},{"id":"minecraft:muddy_mangrove_roots","localizedName":"Muddy Mangrove Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.muddy_mangrove_roots"},{"id":"minecraft:mule_spawn_egg","localizedName":"Mule Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mule_spawn_egg"},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mushroom_stem"},{"id":"minecraft:mushroom_stew","localizedName":"Mushroom Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.mushroom_stew"},{"id":"minecraft:music_disc_11","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_11"},{"id":"minecraft:music_disc_13","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_13"},{"id":"minecraft:music_disc_5","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_5"},{"id":"minecraft:music_disc_blocks","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_blocks"},{"id":"minecraft:music_disc_cat","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_cat"},{"id":"minecraft:music_disc_chirp","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_chirp"},{"id":"minecraft:music_disc_far","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_far"},{"id":"minecraft:music_disc_mall","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mall"},{"id":"minecraft:music_disc_mellohi","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mellohi"},{"id":"minecraft:music_disc_otherside","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_otherside"},{"id":"minecraft:music_disc_pigstep","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_pigstep"},{"id":"minecraft:music_disc_stal","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_stal"},{"id":"minecraft:music_disc_strad","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_strad"},{"id":"minecraft:music_disc_wait","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_wait"},{"id":"minecraft:music_disc_ward","localizedName":"Music Disc","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_ward"},{"id":"minecraft:mutton","localizedName":"Raw Mutton","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.mutton"},{"id":"minecraft:mycelium","localizedName":"Mycelium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.mycelium"},{"id":"minecraft:name_tag","localizedName":"Name Tag","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.name_tag"},{"id":"minecraft:nautilus_shell","localizedName":"Nautilus Shell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nautilus_shell"},{"id":"minecraft:nether_brick","localizedName":"Nether Brick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_brick"},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_fence"},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_slab"},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_stairs"},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_wall"},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_bricks"},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_gold_ore"},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_quartz_ore"},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_sprouts"},{"id":"minecraft:nether_star","localizedName":"Nether Star","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_star"},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.nether_wart"},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.nether_wart_block"},{"id":"minecraft:netherite_axe","localizedName":"Netherite Axe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_axe"},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.netherite_block"},{"id":"minecraft:netherite_boots","localizedName":"Netherite Boots","maxDamage":481,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_boots"},{"id":"minecraft:netherite_chestplate","localizedName":"Netherite Chestplate","maxDamage":592,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_chestplate"},{"id":"minecraft:netherite_helmet","localizedName":"Netherite Helmet","maxDamage":407,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_helmet"},{"id":"minecraft:netherite_hoe","localizedName":"Netherite Hoe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_hoe"},{"id":"minecraft:netherite_ingot","localizedName":"Netherite Ingot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_ingot"},{"id":"minecraft:netherite_leggings","localizedName":"Netherite Leggings","maxDamage":555,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_leggings"},{"id":"minecraft:netherite_pickaxe","localizedName":"Netherite Pickaxe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_pickaxe"},{"id":"minecraft:netherite_scrap","localizedName":"Netherite Scrap","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_scrap"},{"id":"minecraft:netherite_shovel","localizedName":"Netherite Shovel","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_shovel"},{"id":"minecraft:netherite_sword","localizedName":"Netherite Sword","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_sword"},{"id":"minecraft:netherrack","localizedName":"Netherrack","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.netherrack"},{"id":"minecraft:note_block","localizedName":"Note Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.note_block"},{"id":"minecraft:oak_boat","localizedName":"Oak Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.oak_boat"},{"id":"minecraft:oak_button","localizedName":"Oak Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_button"},{"id":"minecraft:oak_chest_boat","localizedName":"Oak Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.oak_chest_boat"},{"id":"minecraft:oak_door","localizedName":"Oak Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_door"},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence"},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence_gate"},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_leaves"},{"id":"minecraft:oak_log","localizedName":"Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_log"},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_planks"},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_pressure_plate"},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_sapling"},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.oak_sign"},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_slab"},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_stairs"},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_trapdoor"},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oak_wood"},{"id":"minecraft:observer","localizedName":"Observer","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.observer"},{"id":"minecraft:obsidian","localizedName":"Obsidian","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.obsidian"},{"id":"minecraft:ocelot_spawn_egg","localizedName":"Ocelot Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ocelot_spawn_egg"},{"id":"minecraft:ochre_froglight","localizedName":"Ochre Froglight","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.ochre_froglight"},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.orange_banner"},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.orange_bed"},{"id":"minecraft:orange_candle","localizedName":"Orange Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_candle"},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_carpet"},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete"},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete_powder"},{"id":"minecraft:orange_dye","localizedName":"Orange Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.orange_dye"},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_glazed_terracotta"},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.orange_shulker_box"},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass"},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass_pane"},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_terracotta"},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_tulip"},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.orange_wool"},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxeye_daisy"},{"id":"minecraft:oxidized_copper","localizedName":"Oxidized Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_copper"},{"id":"minecraft:oxidized_cut_copper","localizedName":"Oxidized Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper"},{"id":"minecraft:oxidized_cut_copper_slab","localizedName":"Oxidized Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper_slab"},{"id":"minecraft:oxidized_cut_copper_stairs","localizedName":"Oxidized Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper_stairs"},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.packed_ice"},{"id":"minecraft:packed_mud","localizedName":"Packed Mud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.packed_mud"},{"id":"minecraft:painting","localizedName":"Painting","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.painting"},{"id":"minecraft:panda_spawn_egg","localizedName":"Panda Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.panda_spawn_egg"},{"id":"minecraft:paper","localizedName":"Paper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.paper"},{"id":"minecraft:parrot_spawn_egg","localizedName":"Parrot Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.parrot_spawn_egg"},{"id":"minecraft:pearlescent_froglight","localizedName":"Pearlescent Froglight","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pearlescent_froglight"},{"id":"minecraft:peony","localizedName":"Peony","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.peony"},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.petrified_oak_slab"},{"id":"minecraft:phantom_membrane","localizedName":"Phantom Membrane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_membrane"},{"id":"minecraft:phantom_spawn_egg","localizedName":"Phantom Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_spawn_egg"},{"id":"minecraft:pig_spawn_egg","localizedName":"Pig Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pig_spawn_egg"},{"id":"minecraft:piglin_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.piglin_banner_pattern"},{"id":"minecraft:piglin_brute_spawn_egg","localizedName":"Piglin Brute Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_brute_spawn_egg"},{"id":"minecraft:piglin_spawn_egg","localizedName":"Piglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_spawn_egg"},{"id":"minecraft:pillager_spawn_egg","localizedName":"Pillager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pillager_spawn_egg"},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.pink_banner"},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.pink_bed"},{"id":"minecraft:pink_candle","localizedName":"Pink Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_candle"},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_carpet"},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete"},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete_powder"},{"id":"minecraft:pink_dye","localizedName":"Pink Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pink_dye"},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_glazed_terracotta"},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.pink_shulker_box"},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass"},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass_pane"},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_terracotta"},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_tulip"},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pink_wool"},{"id":"minecraft:piston","localizedName":"Piston","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.piston"},{"id":"minecraft:player_head","localizedName":"Player Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.player_head"},{"id":"minecraft:podzol","localizedName":"Podzol","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.podzol"},{"id":"minecraft:pointed_dripstone","localizedName":"Pointed Dripstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pointed_dripstone"},{"id":"minecraft:poisonous_potato","localizedName":"Poisonous Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.poisonous_potato"},{"id":"minecraft:polar_bear_spawn_egg","localizedName":"Polar Bear Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.polar_bear_spawn_egg"},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite"},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_slab"},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_stairs"},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_basalt"},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone"},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_slab"},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_stairs"},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_wall"},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_bricks"},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_button"},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_pressure_plate"},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_slab"},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_stairs"},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_wall"},{"id":"minecraft:polished_deepslate","localizedName":"Polished Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate"},{"id":"minecraft:polished_deepslate_slab","localizedName":"Polished Deepslate Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_slab"},{"id":"minecraft:polished_deepslate_stairs","localizedName":"Polished Deepslate Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_stairs"},{"id":"minecraft:polished_deepslate_wall","localizedName":"Polished Deepslate Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_wall"},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite"},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_slab"},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_stairs"},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite"},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_slab"},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_stairs"},{"id":"minecraft:popped_chorus_fruit","localizedName":"Popped Chorus Fruit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.popped_chorus_fruit"},{"id":"minecraft:poppy","localizedName":"Poppy","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.poppy"},{"id":"minecraft:porkchop","localizedName":"Raw Porkchop","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.porkchop"},{"id":"minecraft:potato","localizedName":"Potato","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.potato"},{"id":"minecraft:potion","localizedName":"Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.potion.effect.water"},{"id":"minecraft:powder_snow_bucket","localizedName":"Powder Snow Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.powder_snow_bucket"},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.powered_rail"},{"id":"minecraft:prismarine","localizedName":"Prismarine","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine"},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_slab"},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_stairs"},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_bricks"},{"id":"minecraft:prismarine_crystals","localizedName":"Prismarine Crystals","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_crystals"},{"id":"minecraft:prismarine_shard","localizedName":"Prismarine Shard","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_shard"},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_slab"},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_stairs"},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_wall"},{"id":"minecraft:pufferfish","localizedName":"Pufferfish","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish"},{"id":"minecraft:pufferfish_bucket","localizedName":"Bucket of Pufferfish","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.pufferfish_bucket"},{"id":"minecraft:pufferfish_spawn_egg","localizedName":"Pufferfish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish_spawn_egg"},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.pumpkin"},{"id":"minecraft:pumpkin_pie","localizedName":"Pumpkin Pie","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_pie"},{"id":"minecraft:pumpkin_seeds","localizedName":"Pumpkin Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_seeds"},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.purple_banner"},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.purple_bed"},{"id":"minecraft:purple_candle","localizedName":"Purple Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_candle"},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_carpet"},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete"},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete_powder"},{"id":"minecraft:purple_dye","localizedName":"Purple Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.purple_dye"},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_glazed_terracotta"},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.purple_shulker_box"},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass"},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass_pane"},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_terracotta"},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purple_wool"},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_block"},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_pillar"},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_slab"},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_stairs"},{"id":"minecraft:quartz","localizedName":"Nether Quartz","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.quartz"},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_block"},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_bricks"},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_pillar"},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_slab"},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_stairs"},{"id":"minecraft:rabbit","localizedName":"Raw Rabbit","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit"},{"id":"minecraft:rabbit_foot","localizedName":"Rabbit\u0027s Foot","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_foot"},{"id":"minecraft:rabbit_hide","localizedName":"Rabbit Hide","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_hide"},{"id":"minecraft:rabbit_spawn_egg","localizedName":"Rabbit Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_spawn_egg"},{"id":"minecraft:rabbit_stew","localizedName":"Rabbit Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.rabbit_stew"},{"id":"minecraft:rail","localizedName":"Rail","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rail"},{"id":"minecraft:ravager_spawn_egg","localizedName":"Ravager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.ravager_spawn_egg"},{"id":"minecraft:raw_copper","localizedName":"Raw Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.raw_copper"},{"id":"minecraft:raw_copper_block","localizedName":"Block of Raw Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.raw_copper_block"},{"id":"minecraft:raw_gold","localizedName":"Raw Gold","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.raw_gold"},{"id":"minecraft:raw_gold_block","localizedName":"Block of Raw Gold","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.raw_gold_block"},{"id":"minecraft:raw_iron","localizedName":"Raw Iron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.raw_iron"},{"id":"minecraft:raw_iron_block","localizedName":"Block of Raw Iron","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.raw_iron_block"},{"id":"minecraft:recovery_compass","localizedName":"Recovery Compass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.recovery_compass"},{"id":"minecraft:red_banner","localizedName":"Red Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.red_banner"},{"id":"minecraft:red_bed","localizedName":"Red Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.red_bed"},{"id":"minecraft:red_candle","localizedName":"Red Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_candle"},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_carpet"},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete"},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete_powder"},{"id":"minecraft:red_dye","localizedName":"Red Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.red_dye"},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_glazed_terracotta"},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom"},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom_block"},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_slab"},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_stairs"},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_wall"},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_bricks"},{"id":"minecraft:red_sand","localizedName":"Red Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sand"},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone"},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_slab"},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_stairs"},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_wall"},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.red_shulker_box"},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass"},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass_pane"},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_terracotta"},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_tulip"},{"id":"minecraft:red_wool","localizedName":"Red Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.red_wool"},{"id":"minecraft:redstone","localizedName":"Redstone Dust","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.redstone"},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_block"},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_lamp"},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_ore"},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_torch"},{"id":"minecraft:reinforced_deepslate","localizedName":"Reinforced Deepslate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.reinforced_deepslate"},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.repeater"},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.repeating_command_block"},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.respawn_anchor"},{"id":"minecraft:rooted_dirt","localizedName":"Rooted Dirt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rooted_dirt"},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.rose_bush"},{"id":"minecraft:rotten_flesh","localizedName":"Rotten Flesh","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.rotten_flesh"},{"id":"minecraft:saddle","localizedName":"Saddle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.saddle"},{"id":"minecraft:salmon","localizedName":"Raw Salmon","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.salmon"},{"id":"minecraft:salmon_bucket","localizedName":"Bucket of Salmon","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.salmon_bucket"},{"id":"minecraft:salmon_spawn_egg","localizedName":"Salmon Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.salmon_spawn_egg"},{"id":"minecraft:sand","localizedName":"Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sand"},{"id":"minecraft:sandstone","localizedName":"Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone"},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_slab"},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_stairs"},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_wall"},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.scaffolding"},{"id":"minecraft:sculk","localizedName":"Sculk","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sculk"},{"id":"minecraft:sculk_catalyst","localizedName":"Sculk Catalyst","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_catalyst"},{"id":"minecraft:sculk_sensor","localizedName":"Sculk Sensor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_sensor"},{"id":"minecraft:sculk_shrieker","localizedName":"Sculk Shrieker","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_shrieker"},{"id":"minecraft:sculk_vein","localizedName":"Sculk Vein","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_vein"},{"id":"minecraft:scute","localizedName":"Scute","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.scute"},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sea_lantern"},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sea_pickle"},{"id":"minecraft:seagrass","localizedName":"Seagrass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.seagrass"},{"id":"minecraft:shears","localizedName":"Shears","maxDamage":238,"maxStackSize":1,"unlocalizedName":"item.minecraft.shears"},{"id":"minecraft:sheep_spawn_egg","localizedName":"Sheep Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sheep_spawn_egg"},{"id":"minecraft:shield","localizedName":"Shield","maxDamage":336,"maxStackSize":1,"unlocalizedName":"item.minecraft.shield"},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.shroomlight"},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.shulker_box"},{"id":"minecraft:shulker_shell","localizedName":"Shulker Shell","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_shell"},{"id":"minecraft:shulker_spawn_egg","localizedName":"Shulker Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_spawn_egg"},{"id":"minecraft:silverfish_spawn_egg","localizedName":"Silverfish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.silverfish_spawn_egg"},{"id":"minecraft:skeleton_horse_spawn_egg","localizedName":"Skeleton Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_horse_spawn_egg"},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.skeleton_skull"},{"id":"minecraft:skeleton_spawn_egg","localizedName":"Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_spawn_egg"},{"id":"minecraft:skull_banner_pattern","localizedName":"Banner Pattern","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.skull_banner_pattern"},{"id":"minecraft:slime_ball","localizedName":"Slimeball","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.slime_ball"},{"id":"minecraft:slime_block","localizedName":"Slime Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.slime_block"},{"id":"minecraft:slime_spawn_egg","localizedName":"Slime Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.slime_spawn_egg"},{"id":"minecraft:small_amethyst_bud","localizedName":"Small Amethyst Bud","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.small_amethyst_bud"},{"id":"minecraft:small_dripleaf","localizedName":"Small Dripleaf","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.small_dripleaf"},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smithing_table"},{"id":"minecraft:smoker","localizedName":"Smoker","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smoker"},{"id":"minecraft:smooth_basalt","localizedName":"Smooth Basalt","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_basalt"},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz"},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_slab"},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_stairs"},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone"},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_slab"},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_stairs"},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone"},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_slab"},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_stairs"},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone"},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone_slab"},{"id":"minecraft:snow","localizedName":"Snow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.snow"},{"id":"minecraft:snow_block","localizedName":"Snow Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.snow_block"},{"id":"minecraft:snowball","localizedName":"Snowball","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.snowball"},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_campfire"},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_lantern"},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_sand"},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_soil"},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.soul_torch"},{"id":"minecraft:spawner","localizedName":"Spawner","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spawner"},{"id":"minecraft:spectral_arrow","localizedName":"Spectral Arrow","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spectral_arrow"},{"id":"minecraft:spider_eye","localizedName":"Spider Eye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spider_eye"},{"id":"minecraft:spider_spawn_egg","localizedName":"Spider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.spider_spawn_egg"},{"id":"minecraft:splash_potion","localizedName":"Splash Water Bottle","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.splash_potion.effect.water"},{"id":"minecraft:sponge","localizedName":"Sponge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sponge"},{"id":"minecraft:spore_blossom","localizedName":"Spore Blossom","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spore_blossom"},{"id":"minecraft:spruce_boat","localizedName":"Spruce Boat","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.spruce_boat"},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_button"},{"id":"minecraft:spruce_chest_boat","localizedName":"Spruce Boat with Chest","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.spruce_chest_boat"},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_door"},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence"},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence_gate"},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_leaves"},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_log"},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_planks"},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_pressure_plate"},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_sapling"},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.spruce_sign"},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_slab"},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_stairs"},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_trapdoor"},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_wood"},{"id":"minecraft:spyglass","localizedName":"Spyglass","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.spyglass"},{"id":"minecraft:squid_spawn_egg","localizedName":"Squid Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.squid_spawn_egg"},{"id":"minecraft:stick","localizedName":"Stick","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.stick"},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sticky_piston"},{"id":"minecraft:stone","localizedName":"Stone","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone"},{"id":"minecraft:stone_axe","localizedName":"Stone Axe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_axe"},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_slab"},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_stairs"},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_wall"},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_bricks"},{"id":"minecraft:stone_button","localizedName":"Stone Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_button"},{"id":"minecraft:stone_hoe","localizedName":"Stone Hoe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_hoe"},{"id":"minecraft:stone_pickaxe","localizedName":"Stone Pickaxe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_pickaxe"},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_pressure_plate"},{"id":"minecraft:stone_shovel","localizedName":"Stone Shovel","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_shovel"},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_slab"},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stone_stairs"},{"id":"minecraft:stone_sword","localizedName":"Stone Sword","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_sword"},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stonecutter"},{"id":"minecraft:stray_spawn_egg","localizedName":"Stray Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.stray_spawn_egg"},{"id":"minecraft:strider_spawn_egg","localizedName":"Strider Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.strider_spawn_egg"},{"id":"minecraft:string","localizedName":"String","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.string"},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_log"},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_wood"},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_log"},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_wood"},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_hyphae"},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_stem"},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_log"},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_wood"},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_log"},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_wood"},{"id":"minecraft:stripped_mangrove_log","localizedName":"Stripped Mangrove Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_mangrove_log"},{"id":"minecraft:stripped_mangrove_wood","localizedName":"Stripped Mangrove Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_mangrove_wood"},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_log"},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_wood"},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_log"},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_wood"},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_hyphae"},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_stem"},{"id":"minecraft:structure_block","localizedName":"Structure Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.structure_block"},{"id":"minecraft:structure_void","localizedName":"Structure Void","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.structure_void"},{"id":"minecraft:sugar","localizedName":"Sugar","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sugar"},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sugar_cane"},{"id":"minecraft:sunflower","localizedName":"Sunflower","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.sunflower"},{"id":"minecraft:suspicious_stew","localizedName":"Suspicious Stew","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.suspicious_stew"},{"id":"minecraft:sweet_berries","localizedName":"Sweet Berries","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.sweet_berries"},{"id":"minecraft:tadpole_bucket","localizedName":"Bucket of Tadpole","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.tadpole_bucket"},{"id":"minecraft:tadpole_spawn_egg","localizedName":"Tadpole Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tadpole_spawn_egg"},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tall_grass"},{"id":"minecraft:target","localizedName":"Target","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.target"},{"id":"minecraft:terracotta","localizedName":"Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.terracotta"},{"id":"minecraft:tinted_glass","localizedName":"Tinted Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tinted_glass"},{"id":"minecraft:tipped_arrow","localizedName":"Arrow of Poison","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tipped_arrow.effect.poison"},{"id":"minecraft:tnt","localizedName":"TNT","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tnt"},{"id":"minecraft:tnt_minecart","localizedName":"Minecart with TNT","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.tnt_minecart"},{"id":"minecraft:torch","localizedName":"Torch","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.torch"},{"id":"minecraft:totem_of_undying","localizedName":"Totem of Undying","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.totem_of_undying"},{"id":"minecraft:trader_llama_spawn_egg","localizedName":"Trader Llama Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.trader_llama_spawn_egg"},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.trapped_chest"},{"id":"minecraft:trident","localizedName":"Trident","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.trident"},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tripwire_hook"},{"id":"minecraft:tropical_fish","localizedName":"Tropical Fish","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish"},{"id":"minecraft:tropical_fish_bucket","localizedName":"Bucket of Tropical Fish","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.tropical_fish_bucket"},{"id":"minecraft:tropical_fish_spawn_egg","localizedName":"Tropical Fish Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish_spawn_egg"},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral"},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_block"},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_fan"},{"id":"minecraft:tuff","localizedName":"Tuff","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.tuff"},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.turtle_egg"},{"id":"minecraft:turtle_helmet","localizedName":"Turtle Shell","maxDamage":275,"maxStackSize":1,"unlocalizedName":"item.minecraft.turtle_helmet"},{"id":"minecraft:turtle_spawn_egg","localizedName":"Turtle Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.turtle_spawn_egg"},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.twisting_vines"},{"id":"minecraft:verdant_froglight","localizedName":"Verdant Froglight","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.verdant_froglight"},{"id":"minecraft:vex_spawn_egg","localizedName":"Vex Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.vex_spawn_egg"},{"id":"minecraft:villager_spawn_egg","localizedName":"Villager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.villager_spawn_egg"},{"id":"minecraft:vindicator_spawn_egg","localizedName":"Vindicator Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.vindicator_spawn_egg"},{"id":"minecraft:vine","localizedName":"Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.vine"},{"id":"minecraft:wandering_trader_spawn_egg","localizedName":"Wandering Trader Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wandering_trader_spawn_egg"},{"id":"minecraft:warden_spawn_egg","localizedName":"Warden Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.warden_spawn_egg"},{"id":"minecraft:warped_button","localizedName":"Warped Button","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_button"},{"id":"minecraft:warped_door","localizedName":"Warped Door","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_door"},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence"},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence_gate"},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fungus"},{"id":"minecraft:warped_fungus_on_a_stick","localizedName":"Warped Fungus on a Stick","maxDamage":100,"maxStackSize":1,"unlocalizedName":"item.minecraft.warped_fungus_on_a_stick"},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_hyphae"},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_nylium"},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_planks"},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_pressure_plate"},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_roots"},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.warped_sign"},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_slab"},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stairs"},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stem"},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_trapdoor"},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.warped_wart_block"},{"id":"minecraft:water_bucket","localizedName":"Water Bucket","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.water_bucket"},{"id":"minecraft:waxed_copper_block","localizedName":"Waxed Block of Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_copper_block"},{"id":"minecraft:waxed_cut_copper","localizedName":"Waxed Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper"},{"id":"minecraft:waxed_cut_copper_slab","localizedName":"Waxed Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper_slab"},{"id":"minecraft:waxed_cut_copper_stairs","localizedName":"Waxed Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper_stairs"},{"id":"minecraft:waxed_exposed_copper","localizedName":"Waxed Exposed Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_copper"},{"id":"minecraft:waxed_exposed_cut_copper","localizedName":"Waxed Exposed Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper"},{"id":"minecraft:waxed_exposed_cut_copper_slab","localizedName":"Waxed Exposed Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper_slab"},{"id":"minecraft:waxed_exposed_cut_copper_stairs","localizedName":"Waxed Exposed Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper_stairs"},{"id":"minecraft:waxed_oxidized_copper","localizedName":"Waxed Oxidized Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_copper"},{"id":"minecraft:waxed_oxidized_cut_copper","localizedName":"Waxed Oxidized Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper"},{"id":"minecraft:waxed_oxidized_cut_copper_slab","localizedName":"Waxed Oxidized Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper_slab"},{"id":"minecraft:waxed_oxidized_cut_copper_stairs","localizedName":"Waxed Oxidized Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper_stairs"},{"id":"minecraft:waxed_weathered_copper","localizedName":"Waxed Weathered Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_copper"},{"id":"minecraft:waxed_weathered_cut_copper","localizedName":"Waxed Weathered Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper"},{"id":"minecraft:waxed_weathered_cut_copper_slab","localizedName":"Waxed Weathered Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper_slab"},{"id":"minecraft:waxed_weathered_cut_copper_stairs","localizedName":"Waxed Weathered Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper_stairs"},{"id":"minecraft:weathered_copper","localizedName":"Weathered Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_copper"},{"id":"minecraft:weathered_cut_copper","localizedName":"Weathered Cut Copper","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper"},{"id":"minecraft:weathered_cut_copper_slab","localizedName":"Weathered Cut Copper Slab","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper_slab"},{"id":"minecraft:weathered_cut_copper_stairs","localizedName":"Weathered Cut Copper Stairs","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper_stairs"},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.weeping_vines"},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wet_sponge"},{"id":"minecraft:wheat","localizedName":"Wheat","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wheat"},{"id":"minecraft:wheat_seeds","localizedName":"Wheat Seeds","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wheat_seeds"},{"id":"minecraft:white_banner","localizedName":"White Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.white_banner"},{"id":"minecraft:white_bed","localizedName":"White Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.white_bed"},{"id":"minecraft:white_candle","localizedName":"White Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_candle"},{"id":"minecraft:white_carpet","localizedName":"White Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_carpet"},{"id":"minecraft:white_concrete","localizedName":"White Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete"},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete_powder"},{"id":"minecraft:white_dye","localizedName":"White Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.white_dye"},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_glazed_terracotta"},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.white_shulker_box"},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass"},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass_pane"},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_terracotta"},{"id":"minecraft:white_tulip","localizedName":"White Tulip","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_tulip"},{"id":"minecraft:white_wool","localizedName":"White Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.white_wool"},{"id":"minecraft:witch_spawn_egg","localizedName":"Witch Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.witch_spawn_egg"},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wither_rose"},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.wither_skeleton_skull"},{"id":"minecraft:wither_skeleton_spawn_egg","localizedName":"Wither Skeleton Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wither_skeleton_spawn_egg"},{"id":"minecraft:wolf_spawn_egg","localizedName":"Wolf Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.wolf_spawn_egg"},{"id":"minecraft:wooden_axe","localizedName":"Wooden Axe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_axe"},{"id":"minecraft:wooden_hoe","localizedName":"Wooden Hoe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_hoe"},{"id":"minecraft:wooden_pickaxe","localizedName":"Wooden Pickaxe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_pickaxe"},{"id":"minecraft:wooden_shovel","localizedName":"Wooden Shovel","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_shovel"},{"id":"minecraft:wooden_sword","localizedName":"Wooden Sword","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_sword"},{"id":"minecraft:writable_book","localizedName":"Book and Quill","maxDamage":0,"maxStackSize":1,"unlocalizedName":"item.minecraft.writable_book"},{"id":"minecraft:written_book","localizedName":"Written Book","maxDamage":0,"maxStackSize":16,"unlocalizedName":"item.minecraft.written_book"},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","maxDamage":0,"maxStackSize":16,"unlocalizedName":"block.minecraft.yellow_banner"},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_bed"},{"id":"minecraft:yellow_candle","localizedName":"Yellow Candle","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_candle"},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_carpet"},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete"},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete_powder"},{"id":"minecraft:yellow_dye","localizedName":"Yellow Dye","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.yellow_dye"},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_glazed_terracotta"},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","maxDamage":0,"maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_shulker_box"},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass"},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass_pane"},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_terracotta"},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_wool"},{"id":"minecraft:zoglin_spawn_egg","localizedName":"Zoglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zoglin_spawn_egg"},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","maxDamage":0,"maxStackSize":64,"unlocalizedName":"block.minecraft.zombie_head"},{"id":"minecraft:zombie_horse_spawn_egg","localizedName":"Zombie Horse Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_horse_spawn_egg"},{"id":"minecraft:zombie_spawn_egg","localizedName":"Zombie Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_spawn_egg"},{"id":"minecraft:zombie_villager_spawn_egg","localizedName":"Zombie Villager Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_villager_spawn_egg"},{"id":"minecraft:zombified_piglin_spawn_egg","localizedName":"Zombified Piglin Spawn Egg","maxDamage":0,"maxStackSize":64,"unlocalizedName":"item.minecraft.zombified_piglin_spawn_egg"}] diff --git a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.121.json b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.121.json new file mode 100644 index 000000000..aad491aa1 --- /dev/null +++ b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.121.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_boat","localizedName":"Acacia Boat","maxStackSize":1,"unlocalizedName":"item.minecraft.acacia_boat"},{"id":"minecraft:acacia_button","localizedName":"Acacia Button","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_button"},{"id":"minecraft:acacia_chest_boat","localizedName":"Acacia Boat with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.acacia_chest_boat"},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_door"},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence"},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence_gate"},{"id":"minecraft:acacia_hanging_sign","localizedName":"Acacia Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.acacia_hanging_sign"},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_leaves"},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_log"},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_planks"},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_pressure_plate"},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_sapling"},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.acacia_sign"},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_slab"},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_stairs"},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_trapdoor"},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_wood"},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","maxStackSize":64,"unlocalizedName":"block.minecraft.activator_rail"},{"id":"minecraft:air","localizedName":"Air","maxStackSize":64,"unlocalizedName":"block.minecraft.air"},{"id":"minecraft:allay_spawn_egg","localizedName":"Allay Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.allay_spawn_egg"},{"id":"minecraft:allium","localizedName":"Allium","maxStackSize":64,"unlocalizedName":"block.minecraft.allium"},{"id":"minecraft:amethyst_block","localizedName":"Block of Amethyst","maxStackSize":64,"unlocalizedName":"block.minecraft.amethyst_block"},{"id":"minecraft:amethyst_cluster","localizedName":"Amethyst Cluster","maxStackSize":64,"unlocalizedName":"block.minecraft.amethyst_cluster"},{"id":"minecraft:amethyst_shard","localizedName":"Amethyst Shard","maxStackSize":64,"unlocalizedName":"item.minecraft.amethyst_shard"},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","maxStackSize":64,"unlocalizedName":"block.minecraft.ancient_debris"},{"id":"minecraft:andesite","localizedName":"Andesite","maxStackSize":64,"unlocalizedName":"block.minecraft.andesite"},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_slab"},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_stairs"},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_wall"},{"id":"minecraft:angler_pottery_sherd","localizedName":"Angler Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.angler_pottery_sherd"},{"id":"minecraft:anvil","localizedName":"Anvil","maxStackSize":64,"unlocalizedName":"block.minecraft.anvil"},{"id":"minecraft:apple","localizedName":"Apple","maxStackSize":64,"unlocalizedName":"item.minecraft.apple"},{"id":"minecraft:archer_pottery_sherd","localizedName":"Archer Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.archer_pottery_sherd"},{"id":"minecraft:armadillo_scute","localizedName":"Armadillo Scute","maxStackSize":64,"unlocalizedName":"item.minecraft.armadillo_scute"},{"id":"minecraft:armadillo_spawn_egg","localizedName":"Armadillo Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.armadillo_spawn_egg"},{"id":"minecraft:armor_stand","localizedName":"Armor Stand","maxStackSize":16,"unlocalizedName":"item.minecraft.armor_stand"},{"id":"minecraft:arms_up_pottery_sherd","localizedName":"Arms Up Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.arms_up_pottery_sherd"},{"id":"minecraft:arrow","localizedName":"Arrow","maxStackSize":64,"unlocalizedName":"item.minecraft.arrow"},{"id":"minecraft:axolotl_bucket","localizedName":"Bucket of Axolotl","maxStackSize":1,"unlocalizedName":"item.minecraft.axolotl_bucket"},{"id":"minecraft:axolotl_spawn_egg","localizedName":"Axolotl Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.axolotl_spawn_egg"},{"id":"minecraft:azalea","localizedName":"Azalea","maxStackSize":64,"unlocalizedName":"block.minecraft.azalea"},{"id":"minecraft:azalea_leaves","localizedName":"Azalea Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.azalea_leaves"},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","maxStackSize":64,"unlocalizedName":"block.minecraft.azure_bluet"},{"id":"minecraft:baked_potato","localizedName":"Baked Potato","maxStackSize":64,"unlocalizedName":"item.minecraft.baked_potato"},{"id":"minecraft:bamboo","localizedName":"Bamboo","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo"},{"id":"minecraft:bamboo_block","localizedName":"Block of Bamboo","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_block"},{"id":"minecraft:bamboo_button","localizedName":"Bamboo Button","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_button"},{"id":"minecraft:bamboo_chest_raft","localizedName":"Bamboo Raft with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.bamboo_chest_raft"},{"id":"minecraft:bamboo_door","localizedName":"Bamboo Door","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_door"},{"id":"minecraft:bamboo_fence","localizedName":"Bamboo Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_fence"},{"id":"minecraft:bamboo_fence_gate","localizedName":"Bamboo Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_fence_gate"},{"id":"minecraft:bamboo_hanging_sign","localizedName":"Bamboo Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.bamboo_hanging_sign"},{"id":"minecraft:bamboo_mosaic","localizedName":"Bamboo Mosaic","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_mosaic"},{"id":"minecraft:bamboo_mosaic_slab","localizedName":"Bamboo Mosaic Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_mosaic_slab"},{"id":"minecraft:bamboo_mosaic_stairs","localizedName":"Bamboo Mosaic Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_mosaic_stairs"},{"id":"minecraft:bamboo_planks","localizedName":"Bamboo Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_planks"},{"id":"minecraft:bamboo_pressure_plate","localizedName":"Bamboo Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_pressure_plate"},{"id":"minecraft:bamboo_raft","localizedName":"Bamboo Raft","maxStackSize":1,"unlocalizedName":"item.minecraft.bamboo_raft"},{"id":"minecraft:bamboo_sign","localizedName":"Bamboo Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.bamboo_sign"},{"id":"minecraft:bamboo_slab","localizedName":"Bamboo Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_slab"},{"id":"minecraft:bamboo_stairs","localizedName":"Bamboo Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_stairs"},{"id":"minecraft:bamboo_trapdoor","localizedName":"Bamboo Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_trapdoor"},{"id":"minecraft:barrel","localizedName":"Barrel","maxStackSize":64,"unlocalizedName":"block.minecraft.barrel"},{"id":"minecraft:barrier","localizedName":"Barrier","maxStackSize":64,"unlocalizedName":"block.minecraft.barrier"},{"id":"minecraft:basalt","localizedName":"Basalt","maxStackSize":64,"unlocalizedName":"block.minecraft.basalt"},{"id":"minecraft:bat_spawn_egg","localizedName":"Bat Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.bat_spawn_egg"},{"id":"minecraft:beacon","localizedName":"Beacon","maxStackSize":64,"unlocalizedName":"block.minecraft.beacon"},{"id":"minecraft:bedrock","localizedName":"Bedrock","maxStackSize":64,"unlocalizedName":"block.minecraft.bedrock"},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","maxStackSize":64,"unlocalizedName":"block.minecraft.bee_nest"},{"id":"minecraft:bee_spawn_egg","localizedName":"Bee Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.bee_spawn_egg"},{"id":"minecraft:beef","localizedName":"Raw Beef","maxStackSize":64,"unlocalizedName":"item.minecraft.beef"},{"id":"minecraft:beehive","localizedName":"Beehive","maxStackSize":64,"unlocalizedName":"block.minecraft.beehive"},{"id":"minecraft:beetroot","localizedName":"Beetroot","maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot"},{"id":"minecraft:beetroot_seeds","localizedName":"Beetroot Seeds","maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot_seeds"},{"id":"minecraft:beetroot_soup","localizedName":"Beetroot Soup","maxStackSize":1,"unlocalizedName":"item.minecraft.beetroot_soup"},{"id":"minecraft:bell","localizedName":"Bell","maxStackSize":64,"unlocalizedName":"block.minecraft.bell"},{"id":"minecraft:big_dripleaf","localizedName":"Big Dripleaf","maxStackSize":64,"unlocalizedName":"block.minecraft.big_dripleaf"},{"id":"minecraft:birch_boat","localizedName":"Birch Boat","maxStackSize":1,"unlocalizedName":"item.minecraft.birch_boat"},{"id":"minecraft:birch_button","localizedName":"Birch Button","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_button"},{"id":"minecraft:birch_chest_boat","localizedName":"Birch Boat with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.birch_chest_boat"},{"id":"minecraft:birch_door","localizedName":"Birch Door","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_door"},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence"},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence_gate"},{"id":"minecraft:birch_hanging_sign","localizedName":"Birch Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.birch_hanging_sign"},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_leaves"},{"id":"minecraft:birch_log","localizedName":"Birch Log","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_log"},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_planks"},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_pressure_plate"},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_sapling"},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.birch_sign"},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_slab"},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_stairs"},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_trapdoor"},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_wood"},{"id":"minecraft:black_banner","localizedName":"Black Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.black_banner"},{"id":"minecraft:black_bed","localizedName":"Black Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.black_bed"},{"id":"minecraft:black_candle","localizedName":"Black Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.black_candle"},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.black_carpet"},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete"},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete_powder"},{"id":"minecraft:black_dye","localizedName":"Black Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.black_dye"},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.black_glazed_terracotta"},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.black_shulker_box"},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass"},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass_pane"},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.black_terracotta"},{"id":"minecraft:black_wool","localizedName":"Black Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.black_wool"},{"id":"minecraft:blackstone","localizedName":"Blackstone","maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone"},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_slab"},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_stairs"},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_wall"},{"id":"minecraft:blade_pottery_sherd","localizedName":"Blade Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.blade_pottery_sherd"},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","maxStackSize":64,"unlocalizedName":"block.minecraft.blast_furnace"},{"id":"minecraft:blaze_powder","localizedName":"Blaze Powder","maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_powder"},{"id":"minecraft:blaze_rod","localizedName":"Blaze Rod","maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_rod"},{"id":"minecraft:blaze_spawn_egg","localizedName":"Blaze Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_spawn_egg"},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.blue_banner"},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.blue_bed"},{"id":"minecraft:blue_candle","localizedName":"Blue Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_candle"},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_carpet"},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete"},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete_powder"},{"id":"minecraft:blue_dye","localizedName":"Blue Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.blue_dye"},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_glazed_terracotta"},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_ice"},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_orchid"},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.blue_shulker_box"},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass"},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass_pane"},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_terracotta"},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_wool"},{"id":"minecraft:bogged_spawn_egg","localizedName":"Bogged Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.bogged_spawn_egg"},{"id":"minecraft:bolt_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.bolt_armor_trim_smithing_template"},{"id":"minecraft:bone","localizedName":"Bone","maxStackSize":64,"unlocalizedName":"item.minecraft.bone"},{"id":"minecraft:bone_block","localizedName":"Bone Block","maxStackSize":64,"unlocalizedName":"block.minecraft.bone_block"},{"id":"minecraft:bone_meal","localizedName":"Bone Meal","maxStackSize":64,"unlocalizedName":"item.minecraft.bone_meal"},{"id":"minecraft:book","localizedName":"Book","maxStackSize":64,"unlocalizedName":"item.minecraft.book"},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","maxStackSize":64,"unlocalizedName":"block.minecraft.bookshelf"},{"id":"minecraft:bow","localizedName":"Bow","maxDamage":384,"maxStackSize":1,"unlocalizedName":"item.minecraft.bow"},{"id":"minecraft:bowl","localizedName":"Bowl","maxStackSize":64,"unlocalizedName":"item.minecraft.bowl"},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral"},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_block"},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_fan"},{"id":"minecraft:bread","localizedName":"Bread","maxStackSize":64,"unlocalizedName":"item.minecraft.bread"},{"id":"minecraft:breeze_rod","localizedName":"Breeze Rod","maxStackSize":64,"unlocalizedName":"item.minecraft.breeze_rod"},{"id":"minecraft:breeze_spawn_egg","localizedName":"Breeze Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.breeze_spawn_egg"},{"id":"minecraft:brewer_pottery_sherd","localizedName":"Brewer Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.brewer_pottery_sherd"},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","maxStackSize":64,"unlocalizedName":"block.minecraft.brewing_stand"},{"id":"minecraft:brick","localizedName":"Brick","maxStackSize":64,"unlocalizedName":"item.minecraft.brick"},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.brick_slab"},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.brick_stairs"},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.brick_wall"},{"id":"minecraft:bricks","localizedName":"Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.bricks"},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.brown_banner"},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.brown_bed"},{"id":"minecraft:brown_candle","localizedName":"Brown Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_candle"},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_carpet"},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete"},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete_powder"},{"id":"minecraft:brown_dye","localizedName":"Brown Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.brown_dye"},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_glazed_terracotta"},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom"},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom_block"},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.brown_shulker_box"},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass"},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass_pane"},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_terracotta"},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_wool"},{"id":"minecraft:brush","localizedName":"Brush","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.brush"},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral"},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_block"},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_fan"},{"id":"minecraft:bucket","localizedName":"Bucket","maxStackSize":16,"unlocalizedName":"item.minecraft.bucket"},{"id":"minecraft:budding_amethyst","localizedName":"Budding Amethyst","maxStackSize":64,"unlocalizedName":"block.minecraft.budding_amethyst"},{"id":"minecraft:bundle","localizedName":"Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.bundle"},{"id":"minecraft:burn_pottery_sherd","localizedName":"Burn Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.burn_pottery_sherd"},{"id":"minecraft:cactus","localizedName":"Cactus","maxStackSize":64,"unlocalizedName":"block.minecraft.cactus"},{"id":"minecraft:cake","localizedName":"Cake","maxStackSize":1,"unlocalizedName":"block.minecraft.cake"},{"id":"minecraft:calcite","localizedName":"Calcite","maxStackSize":64,"unlocalizedName":"block.minecraft.calcite"},{"id":"minecraft:calibrated_sculk_sensor","localizedName":"Calibrated Sculk Sensor","maxStackSize":64,"unlocalizedName":"block.minecraft.calibrated_sculk_sensor"},{"id":"minecraft:camel_spawn_egg","localizedName":"Camel Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.camel_spawn_egg"},{"id":"minecraft:campfire","localizedName":"Campfire","maxStackSize":64,"unlocalizedName":"block.minecraft.campfire"},{"id":"minecraft:candle","localizedName":"Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.candle"},{"id":"minecraft:carrot","localizedName":"Carrot","maxStackSize":64,"unlocalizedName":"item.minecraft.carrot"},{"id":"minecraft:carrot_on_a_stick","localizedName":"Carrot on a Stick","maxDamage":25,"maxStackSize":1,"unlocalizedName":"item.minecraft.carrot_on_a_stick"},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","maxStackSize":64,"unlocalizedName":"block.minecraft.cartography_table"},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","maxStackSize":64,"unlocalizedName":"block.minecraft.carved_pumpkin"},{"id":"minecraft:cat_spawn_egg","localizedName":"Cat Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.cat_spawn_egg"},{"id":"minecraft:cauldron","localizedName":"Cauldron","maxStackSize":64,"unlocalizedName":"block.minecraft.cauldron"},{"id":"minecraft:cave_spider_spawn_egg","localizedName":"Cave Spider Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.cave_spider_spawn_egg"},{"id":"minecraft:chain","localizedName":"Chain","maxStackSize":64,"unlocalizedName":"block.minecraft.chain"},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","maxStackSize":64,"unlocalizedName":"block.minecraft.chain_command_block"},{"id":"minecraft:chainmail_boots","localizedName":"Chainmail Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_boots"},{"id":"minecraft:chainmail_chestplate","localizedName":"Chainmail Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_chestplate"},{"id":"minecraft:chainmail_helmet","localizedName":"Chainmail Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_helmet"},{"id":"minecraft:chainmail_leggings","localizedName":"Chainmail Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_leggings"},{"id":"minecraft:charcoal","localizedName":"Charcoal","maxStackSize":64,"unlocalizedName":"item.minecraft.charcoal"},{"id":"minecraft:cherry_boat","localizedName":"Cherry Boat","maxStackSize":1,"unlocalizedName":"item.minecraft.cherry_boat"},{"id":"minecraft:cherry_button","localizedName":"Cherry Button","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_button"},{"id":"minecraft:cherry_chest_boat","localizedName":"Cherry Boat with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.cherry_chest_boat"},{"id":"minecraft:cherry_door","localizedName":"Cherry Door","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_door"},{"id":"minecraft:cherry_fence","localizedName":"Cherry Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_fence"},{"id":"minecraft:cherry_fence_gate","localizedName":"Cherry Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_fence_gate"},{"id":"minecraft:cherry_hanging_sign","localizedName":"Cherry Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.cherry_hanging_sign"},{"id":"minecraft:cherry_leaves","localizedName":"Cherry Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_leaves"},{"id":"minecraft:cherry_log","localizedName":"Cherry Log","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_log"},{"id":"minecraft:cherry_planks","localizedName":"Cherry Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_planks"},{"id":"minecraft:cherry_pressure_plate","localizedName":"Cherry Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_pressure_plate"},{"id":"minecraft:cherry_sapling","localizedName":"Cherry Sapling","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_sapling"},{"id":"minecraft:cherry_sign","localizedName":"Cherry Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.cherry_sign"},{"id":"minecraft:cherry_slab","localizedName":"Cherry Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_slab"},{"id":"minecraft:cherry_stairs","localizedName":"Cherry Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_stairs"},{"id":"minecraft:cherry_trapdoor","localizedName":"Cherry Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_trapdoor"},{"id":"minecraft:cherry_wood","localizedName":"Cherry Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_wood"},{"id":"minecraft:chest","localizedName":"Chest","maxStackSize":64,"unlocalizedName":"block.minecraft.chest"},{"id":"minecraft:chest_minecart","localizedName":"Minecart with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.chest_minecart"},{"id":"minecraft:chicken","localizedName":"Raw Chicken","maxStackSize":64,"unlocalizedName":"item.minecraft.chicken"},{"id":"minecraft:chicken_spawn_egg","localizedName":"Chicken Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.chicken_spawn_egg"},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","maxStackSize":64,"unlocalizedName":"block.minecraft.chipped_anvil"},{"id":"minecraft:chiseled_bookshelf","localizedName":"Chiseled Bookshelf","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_bookshelf"},{"id":"minecraft:chiseled_copper","localizedName":"Chiseled Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_copper"},{"id":"minecraft:chiseled_deepslate","localizedName":"Chiseled Deepslate","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_deepslate"},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_nether_bricks"},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_polished_blackstone"},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_quartz_block"},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_red_sandstone"},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_sandstone"},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_stone_bricks"},{"id":"minecraft:chiseled_tuff","localizedName":"Chiseled Tuff","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_tuff"},{"id":"minecraft:chiseled_tuff_bricks","localizedName":"Chiseled Tuff Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_tuff_bricks"},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_flower"},{"id":"minecraft:chorus_fruit","localizedName":"Chorus Fruit","maxStackSize":64,"unlocalizedName":"item.minecraft.chorus_fruit"},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_plant"},{"id":"minecraft:clay","localizedName":"Clay","maxStackSize":64,"unlocalizedName":"block.minecraft.clay"},{"id":"minecraft:clay_ball","localizedName":"Clay Ball","maxStackSize":64,"unlocalizedName":"item.minecraft.clay_ball"},{"id":"minecraft:clock","localizedName":"Clock","maxStackSize":64,"unlocalizedName":"item.minecraft.clock"},{"id":"minecraft:coal","localizedName":"Coal","maxStackSize":64,"unlocalizedName":"item.minecraft.coal"},{"id":"minecraft:coal_block","localizedName":"Block of Coal","maxStackSize":64,"unlocalizedName":"block.minecraft.coal_block"},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.coal_ore"},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","maxStackSize":64,"unlocalizedName":"block.minecraft.coarse_dirt"},{"id":"minecraft:coast_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.coast_armor_trim_smithing_template"},{"id":"minecraft:cobbled_deepslate","localizedName":"Cobbled Deepslate","maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate"},{"id":"minecraft:cobbled_deepslate_slab","localizedName":"Cobbled Deepslate Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_slab"},{"id":"minecraft:cobbled_deepslate_stairs","localizedName":"Cobbled Deepslate Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_stairs"},{"id":"minecraft:cobbled_deepslate_wall","localizedName":"Cobbled Deepslate Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_wall"},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone"},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_slab"},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_stairs"},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_wall"},{"id":"minecraft:cobweb","localizedName":"Cobweb","maxStackSize":64,"unlocalizedName":"block.minecraft.cobweb"},{"id":"minecraft:cocoa_beans","localizedName":"Cocoa Beans","maxStackSize":64,"unlocalizedName":"item.minecraft.cocoa_beans"},{"id":"minecraft:cod","localizedName":"Raw Cod","maxStackSize":64,"unlocalizedName":"item.minecraft.cod"},{"id":"minecraft:cod_bucket","localizedName":"Bucket of Cod","maxStackSize":1,"unlocalizedName":"item.minecraft.cod_bucket"},{"id":"minecraft:cod_spawn_egg","localizedName":"Cod Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.cod_spawn_egg"},{"id":"minecraft:command_block","localizedName":"Command Block","maxStackSize":64,"unlocalizedName":"block.minecraft.command_block"},{"id":"minecraft:command_block_minecart","localizedName":"Minecart with Command Block","maxStackSize":1,"unlocalizedName":"item.minecraft.command_block_minecart"},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","maxStackSize":64,"unlocalizedName":"block.minecraft.comparator"},{"id":"minecraft:compass","localizedName":"Compass","maxStackSize":64,"unlocalizedName":"item.minecraft.compass"},{"id":"minecraft:composter","localizedName":"Composter","maxStackSize":64,"unlocalizedName":"block.minecraft.composter"},{"id":"minecraft:conduit","localizedName":"Conduit","maxStackSize":64,"unlocalizedName":"block.minecraft.conduit"},{"id":"minecraft:cooked_beef","localizedName":"Steak","maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_beef"},{"id":"minecraft:cooked_chicken","localizedName":"Cooked Chicken","maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_chicken"},{"id":"minecraft:cooked_cod","localizedName":"Cooked Cod","maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_cod"},{"id":"minecraft:cooked_mutton","localizedName":"Cooked Mutton","maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_mutton"},{"id":"minecraft:cooked_porkchop","localizedName":"Cooked Porkchop","maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_porkchop"},{"id":"minecraft:cooked_rabbit","localizedName":"Cooked Rabbit","maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_rabbit"},{"id":"minecraft:cooked_salmon","localizedName":"Cooked Salmon","maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_salmon"},{"id":"minecraft:cookie","localizedName":"Cookie","maxStackSize":64,"unlocalizedName":"item.minecraft.cookie"},{"id":"minecraft:copper_block","localizedName":"Block of Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.copper_block"},{"id":"minecraft:copper_bulb","localizedName":"Copper Bulb","maxStackSize":64,"unlocalizedName":"block.minecraft.copper_bulb"},{"id":"minecraft:copper_door","localizedName":"Copper Door","maxStackSize":64,"unlocalizedName":"block.minecraft.copper_door"},{"id":"minecraft:copper_grate","localizedName":"Copper Grate","maxStackSize":64,"unlocalizedName":"block.minecraft.copper_grate"},{"id":"minecraft:copper_ingot","localizedName":"Copper Ingot","maxStackSize":64,"unlocalizedName":"item.minecraft.copper_ingot"},{"id":"minecraft:copper_ore","localizedName":"Copper Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.copper_ore"},{"id":"minecraft:copper_trapdoor","localizedName":"Copper Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.copper_trapdoor"},{"id":"minecraft:cornflower","localizedName":"Cornflower","maxStackSize":64,"unlocalizedName":"block.minecraft.cornflower"},{"id":"minecraft:cow_spawn_egg","localizedName":"Cow Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.cow_spawn_egg"},{"id":"minecraft:cracked_deepslate_bricks","localizedName":"Cracked Deepslate Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_deepslate_bricks"},{"id":"minecraft:cracked_deepslate_tiles","localizedName":"Cracked Deepslate Tiles","maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_deepslate_tiles"},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_nether_bricks"},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_polished_blackstone_bricks"},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_stone_bricks"},{"id":"minecraft:crafter","localizedName":"Crafter","maxStackSize":64,"unlocalizedName":"block.minecraft.crafter"},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","maxStackSize":64,"unlocalizedName":"block.minecraft.crafting_table"},{"id":"minecraft:creeper_banner_pattern","localizedName":"Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.creeper_banner_pattern"},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","maxStackSize":64,"unlocalizedName":"block.minecraft.creeper_head"},{"id":"minecraft:creeper_spawn_egg","localizedName":"Creeper Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.creeper_spawn_egg"},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_button"},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_door"},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence"},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence_gate"},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fungus"},{"id":"minecraft:crimson_hanging_sign","localizedName":"Crimson Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.crimson_hanging_sign"},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_hyphae"},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_nylium"},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_planks"},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_pressure_plate"},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_roots"},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.crimson_sign"},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_slab"},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stairs"},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stem"},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_trapdoor"},{"id":"minecraft:crossbow","localizedName":"Crossbow","maxDamage":465,"maxStackSize":1,"unlocalizedName":"item.minecraft.crossbow"},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","maxStackSize":64,"unlocalizedName":"block.minecraft.crying_obsidian"},{"id":"minecraft:cut_copper","localizedName":"Cut Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper"},{"id":"minecraft:cut_copper_slab","localizedName":"Cut Copper Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper_slab"},{"id":"minecraft:cut_copper_stairs","localizedName":"Cut Copper Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper_stairs"},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone"},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone_slab"},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone"},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone_slab"},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.cyan_banner"},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_bed"},{"id":"minecraft:cyan_candle","localizedName":"Cyan Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_candle"},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_carpet"},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete"},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete_powder"},{"id":"minecraft:cyan_dye","localizedName":"Cyan Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.cyan_dye"},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_glazed_terracotta"},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_shulker_box"},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass"},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass_pane"},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_terracotta"},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_wool"},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","maxStackSize":64,"unlocalizedName":"block.minecraft.damaged_anvil"},{"id":"minecraft:dandelion","localizedName":"Dandelion","maxStackSize":64,"unlocalizedName":"block.minecraft.dandelion"},{"id":"minecraft:danger_pottery_sherd","localizedName":"Danger Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.danger_pottery_sherd"},{"id":"minecraft:dark_oak_boat","localizedName":"Dark Oak Boat","maxStackSize":1,"unlocalizedName":"item.minecraft.dark_oak_boat"},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_button"},{"id":"minecraft:dark_oak_chest_boat","localizedName":"Dark Oak Boat with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.dark_oak_chest_boat"},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_door"},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence"},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence_gate"},{"id":"minecraft:dark_oak_hanging_sign","localizedName":"Dark Oak Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.dark_oak_hanging_sign"},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_leaves"},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_log"},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_planks"},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_pressure_plate"},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_sapling"},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.dark_oak_sign"},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_slab"},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_stairs"},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_trapdoor"},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_wood"},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine"},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_slab"},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_stairs"},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","maxStackSize":64,"unlocalizedName":"block.minecraft.daylight_detector"},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral"},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_block"},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_fan"},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral"},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_block"},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_fan"},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bush"},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral"},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_block"},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_fan"},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral"},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_block"},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_fan"},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral"},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_block"},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_fan"},{"id":"minecraft:debug_stick","localizedName":"Debug Stick","maxStackSize":1,"unlocalizedName":"item.minecraft.debug_stick"},{"id":"minecraft:decorated_pot","localizedName":"Decorated Pot","maxStackSize":64,"unlocalizedName":"block.minecraft.decorated_pot"},{"id":"minecraft:deepslate","localizedName":"Deepslate","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate"},{"id":"minecraft:deepslate_brick_slab","localizedName":"Deepslate Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_slab"},{"id":"minecraft:deepslate_brick_stairs","localizedName":"Deepslate Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_stairs"},{"id":"minecraft:deepslate_brick_wall","localizedName":"Deepslate Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_wall"},{"id":"minecraft:deepslate_bricks","localizedName":"Deepslate Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_bricks"},{"id":"minecraft:deepslate_coal_ore","localizedName":"Deepslate Coal Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_coal_ore"},{"id":"minecraft:deepslate_copper_ore","localizedName":"Deepslate Copper Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_copper_ore"},{"id":"minecraft:deepslate_diamond_ore","localizedName":"Deepslate Diamond Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_diamond_ore"},{"id":"minecraft:deepslate_emerald_ore","localizedName":"Deepslate Emerald Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_emerald_ore"},{"id":"minecraft:deepslate_gold_ore","localizedName":"Deepslate Gold Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_gold_ore"},{"id":"minecraft:deepslate_iron_ore","localizedName":"Deepslate Iron Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_iron_ore"},{"id":"minecraft:deepslate_lapis_ore","localizedName":"Deepslate Lapis Lazuli Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_lapis_ore"},{"id":"minecraft:deepslate_redstone_ore","localizedName":"Deepslate Redstone Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_redstone_ore"},{"id":"minecraft:deepslate_tile_slab","localizedName":"Deepslate Tile Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_slab"},{"id":"minecraft:deepslate_tile_stairs","localizedName":"Deepslate Tile Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_stairs"},{"id":"minecraft:deepslate_tile_wall","localizedName":"Deepslate Tile Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_wall"},{"id":"minecraft:deepslate_tiles","localizedName":"Deepslate Tiles","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tiles"},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","maxStackSize":64,"unlocalizedName":"block.minecraft.detector_rail"},{"id":"minecraft:diamond","localizedName":"Diamond","maxStackSize":64,"unlocalizedName":"item.minecraft.diamond"},{"id":"minecraft:diamond_axe","localizedName":"Diamond Axe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_axe"},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_block"},{"id":"minecraft:diamond_boots","localizedName":"Diamond Boots","maxDamage":429,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_boots"},{"id":"minecraft:diamond_chestplate","localizedName":"Diamond Chestplate","maxDamage":528,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_chestplate"},{"id":"minecraft:diamond_helmet","localizedName":"Diamond Helmet","maxDamage":363,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_helmet"},{"id":"minecraft:diamond_hoe","localizedName":"Diamond Hoe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_hoe"},{"id":"minecraft:diamond_horse_armor","localizedName":"Diamond Horse Armor","maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_horse_armor"},{"id":"minecraft:diamond_leggings","localizedName":"Diamond Leggings","maxDamage":495,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_leggings"},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_ore"},{"id":"minecraft:diamond_pickaxe","localizedName":"Diamond Pickaxe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_pickaxe"},{"id":"minecraft:diamond_shovel","localizedName":"Diamond Shovel","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_shovel"},{"id":"minecraft:diamond_sword","localizedName":"Diamond Sword","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_sword"},{"id":"minecraft:diorite","localizedName":"Diorite","maxStackSize":64,"unlocalizedName":"block.minecraft.diorite"},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_slab"},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_stairs"},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_wall"},{"id":"minecraft:dirt","localizedName":"Dirt","maxStackSize":64,"unlocalizedName":"block.minecraft.dirt"},{"id":"minecraft:dirt_path","localizedName":"Dirt Path","maxStackSize":64,"unlocalizedName":"block.minecraft.dirt_path"},{"id":"minecraft:disc_fragment_5","localizedName":"Disc Fragment","maxStackSize":64,"unlocalizedName":"item.minecraft.disc_fragment_5"},{"id":"minecraft:dispenser","localizedName":"Dispenser","maxStackSize":64,"unlocalizedName":"block.minecraft.dispenser"},{"id":"minecraft:dolphin_spawn_egg","localizedName":"Dolphin Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.dolphin_spawn_egg"},{"id":"minecraft:donkey_spawn_egg","localizedName":"Donkey Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.donkey_spawn_egg"},{"id":"minecraft:dragon_breath","localizedName":"Dragon\u0027s Breath","maxStackSize":64,"unlocalizedName":"item.minecraft.dragon_breath"},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_egg"},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_head"},{"id":"minecraft:dried_kelp","localizedName":"Dried Kelp","maxStackSize":64,"unlocalizedName":"item.minecraft.dried_kelp"},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","maxStackSize":64,"unlocalizedName":"block.minecraft.dried_kelp_block"},{"id":"minecraft:dripstone_block","localizedName":"Dripstone Block","maxStackSize":64,"unlocalizedName":"block.minecraft.dripstone_block"},{"id":"minecraft:dropper","localizedName":"Dropper","maxStackSize":64,"unlocalizedName":"block.minecraft.dropper"},{"id":"minecraft:drowned_spawn_egg","localizedName":"Drowned Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.drowned_spawn_egg"},{"id":"minecraft:dune_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.dune_armor_trim_smithing_template"},{"id":"minecraft:echo_shard","localizedName":"Echo Shard","maxStackSize":64,"unlocalizedName":"item.minecraft.echo_shard"},{"id":"minecraft:egg","localizedName":"Egg","maxStackSize":16,"unlocalizedName":"item.minecraft.egg"},{"id":"minecraft:elder_guardian_spawn_egg","localizedName":"Elder Guardian Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.elder_guardian_spawn_egg"},{"id":"minecraft:elytra","localizedName":"Elytra","maxDamage":432,"maxStackSize":1,"unlocalizedName":"item.minecraft.elytra"},{"id":"minecraft:emerald","localizedName":"Emerald","maxStackSize":64,"unlocalizedName":"item.minecraft.emerald"},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_block"},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_ore"},{"id":"minecraft:enchanted_book","localizedName":"Enchanted Book","maxStackSize":1,"unlocalizedName":"item.minecraft.enchanted_book"},{"id":"minecraft:enchanted_golden_apple","localizedName":"Enchanted Golden Apple","maxStackSize":64,"unlocalizedName":"item.minecraft.enchanted_golden_apple"},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","maxStackSize":64,"unlocalizedName":"block.minecraft.enchanting_table"},{"id":"minecraft:end_crystal","localizedName":"End Crystal","maxStackSize":64,"unlocalizedName":"item.minecraft.end_crystal"},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","maxStackSize":64,"unlocalizedName":"block.minecraft.end_portal_frame"},{"id":"minecraft:end_rod","localizedName":"End Rod","maxStackSize":64,"unlocalizedName":"block.minecraft.end_rod"},{"id":"minecraft:end_stone","localizedName":"End Stone","maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone"},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_slab"},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_stairs"},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_wall"},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_bricks"},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","maxStackSize":64,"unlocalizedName":"block.minecraft.ender_chest"},{"id":"minecraft:ender_dragon_spawn_egg","localizedName":"Ender Dragon Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.ender_dragon_spawn_egg"},{"id":"minecraft:ender_eye","localizedName":"Eye of Ender","maxStackSize":64,"unlocalizedName":"item.minecraft.ender_eye"},{"id":"minecraft:ender_pearl","localizedName":"Ender Pearl","maxStackSize":16,"unlocalizedName":"item.minecraft.ender_pearl"},{"id":"minecraft:enderman_spawn_egg","localizedName":"Enderman Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.enderman_spawn_egg"},{"id":"minecraft:endermite_spawn_egg","localizedName":"Endermite Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.endermite_spawn_egg"},{"id":"minecraft:evoker_spawn_egg","localizedName":"Evoker Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.evoker_spawn_egg"},{"id":"minecraft:experience_bottle","localizedName":"Bottle o\u0027 Enchanting","maxStackSize":64,"unlocalizedName":"item.minecraft.experience_bottle"},{"id":"minecraft:explorer_pottery_sherd","localizedName":"Explorer Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.explorer_pottery_sherd"},{"id":"minecraft:exposed_chiseled_copper","localizedName":"Exposed Chiseled Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_chiseled_copper"},{"id":"minecraft:exposed_copper","localizedName":"Exposed Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_copper"},{"id":"minecraft:exposed_copper_bulb","localizedName":"Exposed Copper Bulb","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_copper_bulb"},{"id":"minecraft:exposed_copper_door","localizedName":"Exposed Copper Door","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_copper_door"},{"id":"minecraft:exposed_copper_grate","localizedName":"Exposed Copper Grate","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_copper_grate"},{"id":"minecraft:exposed_copper_trapdoor","localizedName":"Exposed Copper Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_copper_trapdoor"},{"id":"minecraft:exposed_cut_copper","localizedName":"Exposed Cut Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper"},{"id":"minecraft:exposed_cut_copper_slab","localizedName":"Exposed Cut Copper Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper_slab"},{"id":"minecraft:exposed_cut_copper_stairs","localizedName":"Exposed Cut Copper Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper_stairs"},{"id":"minecraft:eye_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.eye_armor_trim_smithing_template"},{"id":"minecraft:farmland","localizedName":"Farmland","maxStackSize":64,"unlocalizedName":"block.minecraft.farmland"},{"id":"minecraft:feather","localizedName":"Feather","maxStackSize":64,"unlocalizedName":"item.minecraft.feather"},{"id":"minecraft:fermented_spider_eye","localizedName":"Fermented Spider Eye","maxStackSize":64,"unlocalizedName":"item.minecraft.fermented_spider_eye"},{"id":"minecraft:fern","localizedName":"Fern","maxStackSize":64,"unlocalizedName":"block.minecraft.fern"},{"id":"minecraft:filled_map","localizedName":"Map","maxStackSize":64,"unlocalizedName":"item.minecraft.filled_map"},{"id":"minecraft:fire_charge","localizedName":"Fire Charge","maxStackSize":64,"unlocalizedName":"item.minecraft.fire_charge"},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral"},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_block"},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_fan"},{"id":"minecraft:firework_rocket","localizedName":"Firework Rocket","maxStackSize":64,"unlocalizedName":"item.minecraft.firework_rocket"},{"id":"minecraft:firework_star","localizedName":"Firework Star","maxStackSize":64,"unlocalizedName":"item.minecraft.firework_star"},{"id":"minecraft:fishing_rod","localizedName":"Fishing Rod","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.fishing_rod"},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","maxStackSize":64,"unlocalizedName":"block.minecraft.fletching_table"},{"id":"minecraft:flint","localizedName":"Flint","maxStackSize":64,"unlocalizedName":"item.minecraft.flint"},{"id":"minecraft:flint_and_steel","localizedName":"Flint and Steel","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.flint_and_steel"},{"id":"minecraft:flow_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.flow_armor_trim_smithing_template"},{"id":"minecraft:flow_banner_pattern","localizedName":"Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.flow_banner_pattern"},{"id":"minecraft:flow_pottery_sherd","localizedName":"Flow Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.flow_pottery_sherd"},{"id":"minecraft:flower_banner_pattern","localizedName":"Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.flower_banner_pattern"},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","maxStackSize":64,"unlocalizedName":"block.minecraft.flower_pot"},{"id":"minecraft:flowering_azalea","localizedName":"Flowering Azalea","maxStackSize":64,"unlocalizedName":"block.minecraft.flowering_azalea"},{"id":"minecraft:flowering_azalea_leaves","localizedName":"Flowering Azalea Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.flowering_azalea_leaves"},{"id":"minecraft:fox_spawn_egg","localizedName":"Fox Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.fox_spawn_egg"},{"id":"minecraft:friend_pottery_sherd","localizedName":"Friend Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.friend_pottery_sherd"},{"id":"minecraft:frog_spawn_egg","localizedName":"Frog Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.frog_spawn_egg"},{"id":"minecraft:frogspawn","localizedName":"Frogspawn","maxStackSize":64,"unlocalizedName":"block.minecraft.frogspawn"},{"id":"minecraft:furnace","localizedName":"Furnace","maxStackSize":64,"unlocalizedName":"block.minecraft.furnace"},{"id":"minecraft:furnace_minecart","localizedName":"Minecart with Furnace","maxStackSize":1,"unlocalizedName":"item.minecraft.furnace_minecart"},{"id":"minecraft:ghast_spawn_egg","localizedName":"Ghast Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_spawn_egg"},{"id":"minecraft:ghast_tear","localizedName":"Ghast Tear","maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_tear"},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","maxStackSize":64,"unlocalizedName":"block.minecraft.gilded_blackstone"},{"id":"minecraft:glass","localizedName":"Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.glass"},{"id":"minecraft:glass_bottle","localizedName":"Glass Bottle","maxStackSize":64,"unlocalizedName":"item.minecraft.glass_bottle"},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.glass_pane"},{"id":"minecraft:glistering_melon_slice","localizedName":"Glistering Melon Slice","maxStackSize":64,"unlocalizedName":"item.minecraft.glistering_melon_slice"},{"id":"minecraft:globe_banner_pattern","localizedName":"Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.globe_banner_pattern"},{"id":"minecraft:glow_berries","localizedName":"Glow Berries","maxStackSize":64,"unlocalizedName":"item.minecraft.glow_berries"},{"id":"minecraft:glow_ink_sac","localizedName":"Glow Ink Sac","maxStackSize":64,"unlocalizedName":"item.minecraft.glow_ink_sac"},{"id":"minecraft:glow_item_frame","localizedName":"Glow Item Frame","maxStackSize":64,"unlocalizedName":"item.minecraft.glow_item_frame"},{"id":"minecraft:glow_lichen","localizedName":"Glow Lichen","maxStackSize":64,"unlocalizedName":"block.minecraft.glow_lichen"},{"id":"minecraft:glow_squid_spawn_egg","localizedName":"Glow Squid Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.glow_squid_spawn_egg"},{"id":"minecraft:glowstone","localizedName":"Glowstone","maxStackSize":64,"unlocalizedName":"block.minecraft.glowstone"},{"id":"minecraft:glowstone_dust","localizedName":"Glowstone Dust","maxStackSize":64,"unlocalizedName":"item.minecraft.glowstone_dust"},{"id":"minecraft:goat_horn","localizedName":"Goat Horn","maxStackSize":1,"unlocalizedName":"item.minecraft.goat_horn"},{"id":"minecraft:goat_spawn_egg","localizedName":"Goat Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.goat_spawn_egg"},{"id":"minecraft:gold_block","localizedName":"Block of Gold","maxStackSize":64,"unlocalizedName":"block.minecraft.gold_block"},{"id":"minecraft:gold_ingot","localizedName":"Gold Ingot","maxStackSize":64,"unlocalizedName":"item.minecraft.gold_ingot"},{"id":"minecraft:gold_nugget","localizedName":"Gold Nugget","maxStackSize":64,"unlocalizedName":"item.minecraft.gold_nugget"},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.gold_ore"},{"id":"minecraft:golden_apple","localizedName":"Golden Apple","maxStackSize":64,"unlocalizedName":"item.minecraft.golden_apple"},{"id":"minecraft:golden_axe","localizedName":"Golden Axe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_axe"},{"id":"minecraft:golden_boots","localizedName":"Golden Boots","maxDamage":91,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_boots"},{"id":"minecraft:golden_carrot","localizedName":"Golden Carrot","maxStackSize":64,"unlocalizedName":"item.minecraft.golden_carrot"},{"id":"minecraft:golden_chestplate","localizedName":"Golden Chestplate","maxDamage":112,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_chestplate"},{"id":"minecraft:golden_helmet","localizedName":"Golden Helmet","maxDamage":77,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_helmet"},{"id":"minecraft:golden_hoe","localizedName":"Golden Hoe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_hoe"},{"id":"minecraft:golden_horse_armor","localizedName":"Golden Horse Armor","maxStackSize":1,"unlocalizedName":"item.minecraft.golden_horse_armor"},{"id":"minecraft:golden_leggings","localizedName":"Golden Leggings","maxDamage":105,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_leggings"},{"id":"minecraft:golden_pickaxe","localizedName":"Golden Pickaxe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_pickaxe"},{"id":"minecraft:golden_shovel","localizedName":"Golden Shovel","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_shovel"},{"id":"minecraft:golden_sword","localizedName":"Golden Sword","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_sword"},{"id":"minecraft:granite","localizedName":"Granite","maxStackSize":64,"unlocalizedName":"block.minecraft.granite"},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.granite_slab"},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.granite_stairs"},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.granite_wall"},{"id":"minecraft:grass_block","localizedName":"Grass Block","maxStackSize":64,"unlocalizedName":"block.minecraft.grass_block"},{"id":"minecraft:gravel","localizedName":"Gravel","maxStackSize":64,"unlocalizedName":"block.minecraft.gravel"},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.gray_banner"},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.gray_bed"},{"id":"minecraft:gray_candle","localizedName":"Gray Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_candle"},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_carpet"},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete"},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete_powder"},{"id":"minecraft:gray_dye","localizedName":"Gray Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.gray_dye"},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_glazed_terracotta"},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.gray_shulker_box"},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass"},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass_pane"},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_terracotta"},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_wool"},{"id":"minecraft:green_banner","localizedName":"Green Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.green_banner"},{"id":"minecraft:green_bed","localizedName":"Green Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.green_bed"},{"id":"minecraft:green_candle","localizedName":"Green Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.green_candle"},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.green_carpet"},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete"},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete_powder"},{"id":"minecraft:green_dye","localizedName":"Green Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.green_dye"},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.green_glazed_terracotta"},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.green_shulker_box"},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass"},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass_pane"},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.green_terracotta"},{"id":"minecraft:green_wool","localizedName":"Green Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.green_wool"},{"id":"minecraft:grindstone","localizedName":"Grindstone","maxStackSize":64,"unlocalizedName":"block.minecraft.grindstone"},{"id":"minecraft:guardian_spawn_egg","localizedName":"Guardian Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.guardian_spawn_egg"},{"id":"minecraft:gunpowder","localizedName":"Gunpowder","maxStackSize":64,"unlocalizedName":"item.minecraft.gunpowder"},{"id":"minecraft:guster_banner_pattern","localizedName":"Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.guster_banner_pattern"},{"id":"minecraft:guster_pottery_sherd","localizedName":"Guster Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.guster_pottery_sherd"},{"id":"minecraft:hanging_roots","localizedName":"Hanging Roots","maxStackSize":64,"unlocalizedName":"block.minecraft.hanging_roots"},{"id":"minecraft:hay_block","localizedName":"Hay Bale","maxStackSize":64,"unlocalizedName":"block.minecraft.hay_block"},{"id":"minecraft:heart_of_the_sea","localizedName":"Heart of the Sea","maxStackSize":64,"unlocalizedName":"item.minecraft.heart_of_the_sea"},{"id":"minecraft:heart_pottery_sherd","localizedName":"Heart Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.heart_pottery_sherd"},{"id":"minecraft:heartbreak_pottery_sherd","localizedName":"Heartbreak Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.heartbreak_pottery_sherd"},{"id":"minecraft:heavy_core","localizedName":"Heavy Core","maxStackSize":64,"unlocalizedName":"block.minecraft.heavy_core"},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.heavy_weighted_pressure_plate"},{"id":"minecraft:hoglin_spawn_egg","localizedName":"Hoglin Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.hoglin_spawn_egg"},{"id":"minecraft:honey_block","localizedName":"Honey Block","maxStackSize":64,"unlocalizedName":"block.minecraft.honey_block"},{"id":"minecraft:honey_bottle","localizedName":"Honey Bottle","maxStackSize":16,"unlocalizedName":"item.minecraft.honey_bottle"},{"id":"minecraft:honeycomb","localizedName":"Honeycomb","maxStackSize":64,"unlocalizedName":"item.minecraft.honeycomb"},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","maxStackSize":64,"unlocalizedName":"block.minecraft.honeycomb_block"},{"id":"minecraft:hopper","localizedName":"Hopper","maxStackSize":64,"unlocalizedName":"block.minecraft.hopper"},{"id":"minecraft:hopper_minecart","localizedName":"Minecart with Hopper","maxStackSize":1,"unlocalizedName":"item.minecraft.hopper_minecart"},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral"},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_block"},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_fan"},{"id":"minecraft:horse_spawn_egg","localizedName":"Horse Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.horse_spawn_egg"},{"id":"minecraft:host_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.host_armor_trim_smithing_template"},{"id":"minecraft:howl_pottery_sherd","localizedName":"Howl Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.howl_pottery_sherd"},{"id":"minecraft:husk_spawn_egg","localizedName":"Husk Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.husk_spawn_egg"},{"id":"minecraft:ice","localizedName":"Ice","maxStackSize":64,"unlocalizedName":"block.minecraft.ice"},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.infested_chiseled_stone_bricks"},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cobblestone"},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cracked_stone_bricks"},{"id":"minecraft:infested_deepslate","localizedName":"Infested Deepslate","maxStackSize":64,"unlocalizedName":"block.minecraft.infested_deepslate"},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.infested_mossy_stone_bricks"},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone"},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone_bricks"},{"id":"minecraft:ink_sac","localizedName":"Ink Sac","maxStackSize":64,"unlocalizedName":"item.minecraft.ink_sac"},{"id":"minecraft:iron_axe","localizedName":"Iron Axe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_axe"},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","maxStackSize":64,"unlocalizedName":"block.minecraft.iron_bars"},{"id":"minecraft:iron_block","localizedName":"Block of Iron","maxStackSize":64,"unlocalizedName":"block.minecraft.iron_block"},{"id":"minecraft:iron_boots","localizedName":"Iron Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_boots"},{"id":"minecraft:iron_chestplate","localizedName":"Iron Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_chestplate"},{"id":"minecraft:iron_door","localizedName":"Iron Door","maxStackSize":64,"unlocalizedName":"block.minecraft.iron_door"},{"id":"minecraft:iron_golem_spawn_egg","localizedName":"Iron Golem Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.iron_golem_spawn_egg"},{"id":"minecraft:iron_helmet","localizedName":"Iron Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_helmet"},{"id":"minecraft:iron_hoe","localizedName":"Iron Hoe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_hoe"},{"id":"minecraft:iron_horse_armor","localizedName":"Iron Horse Armor","maxStackSize":1,"unlocalizedName":"item.minecraft.iron_horse_armor"},{"id":"minecraft:iron_ingot","localizedName":"Iron Ingot","maxStackSize":64,"unlocalizedName":"item.minecraft.iron_ingot"},{"id":"minecraft:iron_leggings","localizedName":"Iron Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_leggings"},{"id":"minecraft:iron_nugget","localizedName":"Iron Nugget","maxStackSize":64,"unlocalizedName":"item.minecraft.iron_nugget"},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.iron_ore"},{"id":"minecraft:iron_pickaxe","localizedName":"Iron Pickaxe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_pickaxe"},{"id":"minecraft:iron_shovel","localizedName":"Iron Shovel","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_shovel"},{"id":"minecraft:iron_sword","localizedName":"Iron Sword","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_sword"},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.iron_trapdoor"},{"id":"minecraft:item_frame","localizedName":"Item Frame","maxStackSize":64,"unlocalizedName":"item.minecraft.item_frame"},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o\u0027Lantern","maxStackSize":64,"unlocalizedName":"block.minecraft.jack_o_lantern"},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","maxStackSize":64,"unlocalizedName":"block.minecraft.jigsaw"},{"id":"minecraft:jukebox","localizedName":"Jukebox","maxStackSize":64,"unlocalizedName":"block.minecraft.jukebox"},{"id":"minecraft:jungle_boat","localizedName":"Jungle Boat","maxStackSize":1,"unlocalizedName":"item.minecraft.jungle_boat"},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_button"},{"id":"minecraft:jungle_chest_boat","localizedName":"Jungle Boat with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.jungle_chest_boat"},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_door"},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence"},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence_gate"},{"id":"minecraft:jungle_hanging_sign","localizedName":"Jungle Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.jungle_hanging_sign"},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_leaves"},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_log"},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_planks"},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_pressure_plate"},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_sapling"},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.jungle_sign"},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_slab"},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_stairs"},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_trapdoor"},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_wood"},{"id":"minecraft:kelp","localizedName":"Kelp","maxStackSize":64,"unlocalizedName":"block.minecraft.kelp"},{"id":"minecraft:knowledge_book","localizedName":"Knowledge Book","maxStackSize":1,"unlocalizedName":"item.minecraft.knowledge_book"},{"id":"minecraft:ladder","localizedName":"Ladder","maxStackSize":64,"unlocalizedName":"block.minecraft.ladder"},{"id":"minecraft:lantern","localizedName":"Lantern","maxStackSize":64,"unlocalizedName":"block.minecraft.lantern"},{"id":"minecraft:lapis_block","localizedName":"Block of Lapis Lazuli","maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_block"},{"id":"minecraft:lapis_lazuli","localizedName":"Lapis Lazuli","maxStackSize":64,"unlocalizedName":"item.minecraft.lapis_lazuli"},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_ore"},{"id":"minecraft:large_amethyst_bud","localizedName":"Large Amethyst Bud","maxStackSize":64,"unlocalizedName":"block.minecraft.large_amethyst_bud"},{"id":"minecraft:large_fern","localizedName":"Large Fern","maxStackSize":64,"unlocalizedName":"block.minecraft.large_fern"},{"id":"minecraft:lava_bucket","localizedName":"Lava Bucket","maxStackSize":1,"unlocalizedName":"item.minecraft.lava_bucket"},{"id":"minecraft:lead","localizedName":"Lead","maxStackSize":64,"unlocalizedName":"item.minecraft.lead"},{"id":"minecraft:leather","localizedName":"Leather","maxStackSize":64,"unlocalizedName":"item.minecraft.leather"},{"id":"minecraft:leather_boots","localizedName":"Leather Boots","maxDamage":65,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_boots"},{"id":"minecraft:leather_chestplate","localizedName":"Leather Tunic","maxDamage":80,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_chestplate"},{"id":"minecraft:leather_helmet","localizedName":"Leather Cap","maxDamage":55,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_helmet"},{"id":"minecraft:leather_horse_armor","localizedName":"Leather Horse Armor","maxStackSize":1,"unlocalizedName":"item.minecraft.leather_horse_armor"},{"id":"minecraft:leather_leggings","localizedName":"Leather Pants","maxDamage":75,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_leggings"},{"id":"minecraft:lectern","localizedName":"Lectern","maxStackSize":64,"unlocalizedName":"block.minecraft.lectern"},{"id":"minecraft:lever","localizedName":"Lever","maxStackSize":64,"unlocalizedName":"block.minecraft.lever"},{"id":"minecraft:light","localizedName":"Light","maxStackSize":64,"unlocalizedName":"block.minecraft.light"},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.light_blue_banner"},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_bed"},{"id":"minecraft:light_blue_candle","localizedName":"Light Blue Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_candle"},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_carpet"},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete"},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete_powder"},{"id":"minecraft:light_blue_dye","localizedName":"Light Blue Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.light_blue_dye"},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_glazed_terracotta"},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_shulker_box"},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass"},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass_pane"},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_terracotta"},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_wool"},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.light_gray_banner"},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_bed"},{"id":"minecraft:light_gray_candle","localizedName":"Light Gray Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_candle"},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_carpet"},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete"},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete_powder"},{"id":"minecraft:light_gray_dye","localizedName":"Light Gray Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.light_gray_dye"},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_glazed_terracotta"},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_shulker_box"},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass"},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass_pane"},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_terracotta"},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_wool"},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.light_weighted_pressure_plate"},{"id":"minecraft:lightning_rod","localizedName":"Lightning Rod","maxStackSize":64,"unlocalizedName":"block.minecraft.lightning_rod"},{"id":"minecraft:lilac","localizedName":"Lilac","maxStackSize":64,"unlocalizedName":"block.minecraft.lilac"},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","maxStackSize":64,"unlocalizedName":"block.minecraft.lily_of_the_valley"},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","maxStackSize":64,"unlocalizedName":"block.minecraft.lily_pad"},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.lime_banner"},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.lime_bed"},{"id":"minecraft:lime_candle","localizedName":"Lime Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_candle"},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_carpet"},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete"},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete_powder"},{"id":"minecraft:lime_dye","localizedName":"Lime Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.lime_dye"},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_glazed_terracotta"},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.lime_shulker_box"},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass"},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass_pane"},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_terracotta"},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_wool"},{"id":"minecraft:lingering_potion","localizedName":"Lingering Water Bottle","maxStackSize":1,"unlocalizedName":"item.minecraft.lingering_potion.effect.water"},{"id":"minecraft:llama_spawn_egg","localizedName":"Llama Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.llama_spawn_egg"},{"id":"minecraft:lodestone","localizedName":"Lodestone","maxStackSize":64,"unlocalizedName":"block.minecraft.lodestone"},{"id":"minecraft:loom","localizedName":"Loom","maxStackSize":64,"unlocalizedName":"block.minecraft.loom"},{"id":"minecraft:mace","localizedName":"Mace","maxDamage":500,"maxStackSize":1,"unlocalizedName":"item.minecraft.mace"},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.magenta_banner"},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_bed"},{"id":"minecraft:magenta_candle","localizedName":"Magenta Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_candle"},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_carpet"},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete"},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete_powder"},{"id":"minecraft:magenta_dye","localizedName":"Magenta Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.magenta_dye"},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_glazed_terracotta"},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_shulker_box"},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass"},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass_pane"},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_terracotta"},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_wool"},{"id":"minecraft:magma_block","localizedName":"Magma Block","maxStackSize":64,"unlocalizedName":"block.minecraft.magma_block"},{"id":"minecraft:magma_cream","localizedName":"Magma Cream","maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cream"},{"id":"minecraft:magma_cube_spawn_egg","localizedName":"Magma Cube Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cube_spawn_egg"},{"id":"minecraft:mangrove_boat","localizedName":"Mangrove Boat","maxStackSize":1,"unlocalizedName":"item.minecraft.mangrove_boat"},{"id":"minecraft:mangrove_button","localizedName":"Mangrove Button","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_button"},{"id":"minecraft:mangrove_chest_boat","localizedName":"Mangrove Boat with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.mangrove_chest_boat"},{"id":"minecraft:mangrove_door","localizedName":"Mangrove Door","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_door"},{"id":"minecraft:mangrove_fence","localizedName":"Mangrove Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_fence"},{"id":"minecraft:mangrove_fence_gate","localizedName":"Mangrove Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_fence_gate"},{"id":"minecraft:mangrove_hanging_sign","localizedName":"Mangrove Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.mangrove_hanging_sign"},{"id":"minecraft:mangrove_leaves","localizedName":"Mangrove Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_leaves"},{"id":"minecraft:mangrove_log","localizedName":"Mangrove Log","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_log"},{"id":"minecraft:mangrove_planks","localizedName":"Mangrove Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_planks"},{"id":"minecraft:mangrove_pressure_plate","localizedName":"Mangrove Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_pressure_plate"},{"id":"minecraft:mangrove_propagule","localizedName":"Mangrove Propagule","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_propagule"},{"id":"minecraft:mangrove_roots","localizedName":"Mangrove Roots","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_roots"},{"id":"minecraft:mangrove_sign","localizedName":"Mangrove Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.mangrove_sign"},{"id":"minecraft:mangrove_slab","localizedName":"Mangrove Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_slab"},{"id":"minecraft:mangrove_stairs","localizedName":"Mangrove Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_stairs"},{"id":"minecraft:mangrove_trapdoor","localizedName":"Mangrove Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_trapdoor"},{"id":"minecraft:mangrove_wood","localizedName":"Mangrove Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_wood"},{"id":"minecraft:map","localizedName":"Empty Map","maxStackSize":64,"unlocalizedName":"item.minecraft.map"},{"id":"minecraft:medium_amethyst_bud","localizedName":"Medium Amethyst Bud","maxStackSize":64,"unlocalizedName":"block.minecraft.medium_amethyst_bud"},{"id":"minecraft:melon","localizedName":"Melon","maxStackSize":64,"unlocalizedName":"block.minecraft.melon"},{"id":"minecraft:melon_seeds","localizedName":"Melon Seeds","maxStackSize":64,"unlocalizedName":"item.minecraft.melon_seeds"},{"id":"minecraft:melon_slice","localizedName":"Melon Slice","maxStackSize":64,"unlocalizedName":"item.minecraft.melon_slice"},{"id":"minecraft:milk_bucket","localizedName":"Milk Bucket","maxStackSize":1,"unlocalizedName":"item.minecraft.milk_bucket"},{"id":"minecraft:minecart","localizedName":"Minecart","maxStackSize":1,"unlocalizedName":"item.minecraft.minecart"},{"id":"minecraft:miner_pottery_sherd","localizedName":"Miner Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.miner_pottery_sherd"},{"id":"minecraft:mojang_banner_pattern","localizedName":"Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.mojang_banner_pattern"},{"id":"minecraft:mooshroom_spawn_egg","localizedName":"Mooshroom Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.mooshroom_spawn_egg"},{"id":"minecraft:moss_block","localizedName":"Moss Block","maxStackSize":64,"unlocalizedName":"block.minecraft.moss_block"},{"id":"minecraft:moss_carpet","localizedName":"Moss Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.moss_carpet"},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone"},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_slab"},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_stairs"},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_wall"},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_slab"},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_stairs"},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_wall"},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_bricks"},{"id":"minecraft:mourner_pottery_sherd","localizedName":"Mourner Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.mourner_pottery_sherd"},{"id":"minecraft:mud","localizedName":"Mud","maxStackSize":64,"unlocalizedName":"block.minecraft.mud"},{"id":"minecraft:mud_brick_slab","localizedName":"Mud Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.mud_brick_slab"},{"id":"minecraft:mud_brick_stairs","localizedName":"Mud Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.mud_brick_stairs"},{"id":"minecraft:mud_brick_wall","localizedName":"Mud Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.mud_brick_wall"},{"id":"minecraft:mud_bricks","localizedName":"Mud Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.mud_bricks"},{"id":"minecraft:muddy_mangrove_roots","localizedName":"Muddy Mangrove Roots","maxStackSize":64,"unlocalizedName":"block.minecraft.muddy_mangrove_roots"},{"id":"minecraft:mule_spawn_egg","localizedName":"Mule Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.mule_spawn_egg"},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","maxStackSize":64,"unlocalizedName":"block.minecraft.mushroom_stem"},{"id":"minecraft:mushroom_stew","localizedName":"Mushroom Stew","maxStackSize":1,"unlocalizedName":"item.minecraft.mushroom_stew"},{"id":"minecraft:music_disc_11","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_11"},{"id":"minecraft:music_disc_13","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_13"},{"id":"minecraft:music_disc_5","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_5"},{"id":"minecraft:music_disc_blocks","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_blocks"},{"id":"minecraft:music_disc_cat","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_cat"},{"id":"minecraft:music_disc_chirp","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_chirp"},{"id":"minecraft:music_disc_creator","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_creator"},{"id":"minecraft:music_disc_creator_music_box","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_creator_music_box"},{"id":"minecraft:music_disc_far","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_far"},{"id":"minecraft:music_disc_mall","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mall"},{"id":"minecraft:music_disc_mellohi","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mellohi"},{"id":"minecraft:music_disc_otherside","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_otherside"},{"id":"minecraft:music_disc_pigstep","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_pigstep"},{"id":"minecraft:music_disc_precipice","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_precipice"},{"id":"minecraft:music_disc_relic","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_relic"},{"id":"minecraft:music_disc_stal","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_stal"},{"id":"minecraft:music_disc_strad","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_strad"},{"id":"minecraft:music_disc_wait","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_wait"},{"id":"minecraft:music_disc_ward","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_ward"},{"id":"minecraft:mutton","localizedName":"Raw Mutton","maxStackSize":64,"unlocalizedName":"item.minecraft.mutton"},{"id":"minecraft:mycelium","localizedName":"Mycelium","maxStackSize":64,"unlocalizedName":"block.minecraft.mycelium"},{"id":"minecraft:name_tag","localizedName":"Name Tag","maxStackSize":64,"unlocalizedName":"item.minecraft.name_tag"},{"id":"minecraft:nautilus_shell","localizedName":"Nautilus Shell","maxStackSize":64,"unlocalizedName":"item.minecraft.nautilus_shell"},{"id":"minecraft:nether_brick","localizedName":"Nether Brick","maxStackSize":64,"unlocalizedName":"item.minecraft.nether_brick"},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_fence"},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_slab"},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_stairs"},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_wall"},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_bricks"},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_gold_ore"},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_quartz_ore"},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_sprouts"},{"id":"minecraft:nether_star","localizedName":"Nether Star","maxStackSize":64,"unlocalizedName":"item.minecraft.nether_star"},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","maxStackSize":64,"unlocalizedName":"item.minecraft.nether_wart"},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_wart_block"},{"id":"minecraft:netherite_axe","localizedName":"Netherite Axe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_axe"},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","maxStackSize":64,"unlocalizedName":"block.minecraft.netherite_block"},{"id":"minecraft:netherite_boots","localizedName":"Netherite Boots","maxDamage":481,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_boots"},{"id":"minecraft:netherite_chestplate","localizedName":"Netherite Chestplate","maxDamage":592,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_chestplate"},{"id":"minecraft:netherite_helmet","localizedName":"Netherite Helmet","maxDamage":407,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_helmet"},{"id":"minecraft:netherite_hoe","localizedName":"Netherite Hoe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_hoe"},{"id":"minecraft:netherite_ingot","localizedName":"Netherite Ingot","maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_ingot"},{"id":"minecraft:netherite_leggings","localizedName":"Netherite Leggings","maxDamage":555,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_leggings"},{"id":"minecraft:netherite_pickaxe","localizedName":"Netherite Pickaxe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_pickaxe"},{"id":"minecraft:netherite_scrap","localizedName":"Netherite Scrap","maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_scrap"},{"id":"minecraft:netherite_shovel","localizedName":"Netherite Shovel","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_shovel"},{"id":"minecraft:netherite_sword","localizedName":"Netherite Sword","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_sword"},{"id":"minecraft:netherite_upgrade_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_upgrade_smithing_template"},{"id":"minecraft:netherrack","localizedName":"Netherrack","maxStackSize":64,"unlocalizedName":"block.minecraft.netherrack"},{"id":"minecraft:note_block","localizedName":"Note Block","maxStackSize":64,"unlocalizedName":"block.minecraft.note_block"},{"id":"minecraft:oak_boat","localizedName":"Oak Boat","maxStackSize":1,"unlocalizedName":"item.minecraft.oak_boat"},{"id":"minecraft:oak_button","localizedName":"Oak Button","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_button"},{"id":"minecraft:oak_chest_boat","localizedName":"Oak Boat with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.oak_chest_boat"},{"id":"minecraft:oak_door","localizedName":"Oak Door","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_door"},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence"},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence_gate"},{"id":"minecraft:oak_hanging_sign","localizedName":"Oak Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.oak_hanging_sign"},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_leaves"},{"id":"minecraft:oak_log","localizedName":"Oak Log","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_log"},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_planks"},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_pressure_plate"},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_sapling"},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.oak_sign"},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_slab"},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_stairs"},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_trapdoor"},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_wood"},{"id":"minecraft:observer","localizedName":"Observer","maxStackSize":64,"unlocalizedName":"block.minecraft.observer"},{"id":"minecraft:obsidian","localizedName":"Obsidian","maxStackSize":64,"unlocalizedName":"block.minecraft.obsidian"},{"id":"minecraft:ocelot_spawn_egg","localizedName":"Ocelot Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.ocelot_spawn_egg"},{"id":"minecraft:ochre_froglight","localizedName":"Ochre Froglight","maxStackSize":64,"unlocalizedName":"block.minecraft.ochre_froglight"},{"id":"minecraft:ominous_bottle","localizedName":"Ominous Bottle","maxStackSize":64,"unlocalizedName":"item.minecraft.ominous_bottle"},{"id":"minecraft:ominous_trial_key","localizedName":"Ominous Trial Key","maxStackSize":64,"unlocalizedName":"item.minecraft.ominous_trial_key"},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.orange_banner"},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.orange_bed"},{"id":"minecraft:orange_candle","localizedName":"Orange Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_candle"},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_carpet"},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete"},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete_powder"},{"id":"minecraft:orange_dye","localizedName":"Orange Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.orange_dye"},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_glazed_terracotta"},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.orange_shulker_box"},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass"},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass_pane"},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_terracotta"},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_tulip"},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_wool"},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","maxStackSize":64,"unlocalizedName":"block.minecraft.oxeye_daisy"},{"id":"minecraft:oxidized_chiseled_copper","localizedName":"Oxidized Chiseled Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_chiseled_copper"},{"id":"minecraft:oxidized_copper","localizedName":"Oxidized Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_copper"},{"id":"minecraft:oxidized_copper_bulb","localizedName":"Oxidized Copper Bulb","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_copper_bulb"},{"id":"minecraft:oxidized_copper_door","localizedName":"Oxidized Copper Door","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_copper_door"},{"id":"minecraft:oxidized_copper_grate","localizedName":"Oxidized Copper Grate","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_copper_grate"},{"id":"minecraft:oxidized_copper_trapdoor","localizedName":"Oxidized Copper Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_copper_trapdoor"},{"id":"minecraft:oxidized_cut_copper","localizedName":"Oxidized Cut Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper"},{"id":"minecraft:oxidized_cut_copper_slab","localizedName":"Oxidized Cut Copper Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper_slab"},{"id":"minecraft:oxidized_cut_copper_stairs","localizedName":"Oxidized Cut Copper Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper_stairs"},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","maxStackSize":64,"unlocalizedName":"block.minecraft.packed_ice"},{"id":"minecraft:packed_mud","localizedName":"Packed Mud","maxStackSize":64,"unlocalizedName":"block.minecraft.packed_mud"},{"id":"minecraft:painting","localizedName":"Painting","maxStackSize":64,"unlocalizedName":"item.minecraft.painting"},{"id":"minecraft:panda_spawn_egg","localizedName":"Panda Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.panda_spawn_egg"},{"id":"minecraft:paper","localizedName":"Paper","maxStackSize":64,"unlocalizedName":"item.minecraft.paper"},{"id":"minecraft:parrot_spawn_egg","localizedName":"Parrot Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.parrot_spawn_egg"},{"id":"minecraft:pearlescent_froglight","localizedName":"Pearlescent Froglight","maxStackSize":64,"unlocalizedName":"block.minecraft.pearlescent_froglight"},{"id":"minecraft:peony","localizedName":"Peony","maxStackSize":64,"unlocalizedName":"block.minecraft.peony"},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.petrified_oak_slab"},{"id":"minecraft:phantom_membrane","localizedName":"Phantom Membrane","maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_membrane"},{"id":"minecraft:phantom_spawn_egg","localizedName":"Phantom Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_spawn_egg"},{"id":"minecraft:pig_spawn_egg","localizedName":"Pig Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.pig_spawn_egg"},{"id":"minecraft:piglin_banner_pattern","localizedName":"Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.piglin_banner_pattern"},{"id":"minecraft:piglin_brute_spawn_egg","localizedName":"Piglin Brute Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_brute_spawn_egg"},{"id":"minecraft:piglin_head","localizedName":"Piglin Head","maxStackSize":64,"unlocalizedName":"block.minecraft.piglin_head"},{"id":"minecraft:piglin_spawn_egg","localizedName":"Piglin Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_spawn_egg"},{"id":"minecraft:pillager_spawn_egg","localizedName":"Pillager Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.pillager_spawn_egg"},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.pink_banner"},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.pink_bed"},{"id":"minecraft:pink_candle","localizedName":"Pink Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_candle"},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_carpet"},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete"},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete_powder"},{"id":"minecraft:pink_dye","localizedName":"Pink Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.pink_dye"},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_glazed_terracotta"},{"id":"minecraft:pink_petals","localizedName":"Pink Petals","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_petals"},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.pink_shulker_box"},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass"},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass_pane"},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_terracotta"},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_tulip"},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_wool"},{"id":"minecraft:piston","localizedName":"Piston","maxStackSize":64,"unlocalizedName":"block.minecraft.piston"},{"id":"minecraft:pitcher_plant","localizedName":"Pitcher Plant","maxStackSize":64,"unlocalizedName":"block.minecraft.pitcher_plant"},{"id":"minecraft:pitcher_pod","localizedName":"Pitcher Pod","maxStackSize":64,"unlocalizedName":"item.minecraft.pitcher_pod"},{"id":"minecraft:player_head","localizedName":"Player Head","maxStackSize":64,"unlocalizedName":"block.minecraft.player_head"},{"id":"minecraft:plenty_pottery_sherd","localizedName":"Plenty Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.plenty_pottery_sherd"},{"id":"minecraft:podzol","localizedName":"Podzol","maxStackSize":64,"unlocalizedName":"block.minecraft.podzol"},{"id":"minecraft:pointed_dripstone","localizedName":"Pointed Dripstone","maxStackSize":64,"unlocalizedName":"block.minecraft.pointed_dripstone"},{"id":"minecraft:poisonous_potato","localizedName":"Poisonous Potato","maxStackSize":64,"unlocalizedName":"item.minecraft.poisonous_potato"},{"id":"minecraft:polar_bear_spawn_egg","localizedName":"Polar Bear Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.polar_bear_spawn_egg"},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite"},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_slab"},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_stairs"},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_basalt"},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone"},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_slab"},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_stairs"},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_wall"},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_bricks"},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_button"},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_pressure_plate"},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_slab"},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_stairs"},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_wall"},{"id":"minecraft:polished_deepslate","localizedName":"Polished Deepslate","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate"},{"id":"minecraft:polished_deepslate_slab","localizedName":"Polished Deepslate Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_slab"},{"id":"minecraft:polished_deepslate_stairs","localizedName":"Polished Deepslate Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_stairs"},{"id":"minecraft:polished_deepslate_wall","localizedName":"Polished Deepslate Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_wall"},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite"},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_slab"},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_stairs"},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite"},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_slab"},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_stairs"},{"id":"minecraft:polished_tuff","localizedName":"Polished Tuff","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_tuff"},{"id":"minecraft:polished_tuff_slab","localizedName":"Polished Tuff Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_tuff_slab"},{"id":"minecraft:polished_tuff_stairs","localizedName":"Polished Tuff Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_tuff_stairs"},{"id":"minecraft:polished_tuff_wall","localizedName":"Polished Tuff Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_tuff_wall"},{"id":"minecraft:popped_chorus_fruit","localizedName":"Popped Chorus Fruit","maxStackSize":64,"unlocalizedName":"item.minecraft.popped_chorus_fruit"},{"id":"minecraft:poppy","localizedName":"Poppy","maxStackSize":64,"unlocalizedName":"block.minecraft.poppy"},{"id":"minecraft:porkchop","localizedName":"Raw Porkchop","maxStackSize":64,"unlocalizedName":"item.minecraft.porkchop"},{"id":"minecraft:potato","localizedName":"Potato","maxStackSize":64,"unlocalizedName":"item.minecraft.potato"},{"id":"minecraft:potion","localizedName":"Water Bottle","maxStackSize":1,"unlocalizedName":"item.minecraft.potion.effect.water"},{"id":"minecraft:powder_snow_bucket","localizedName":"Powder Snow Bucket","maxStackSize":1,"unlocalizedName":"item.minecraft.powder_snow_bucket"},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","maxStackSize":64,"unlocalizedName":"block.minecraft.powered_rail"},{"id":"minecraft:prismarine","localizedName":"Prismarine","maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine"},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_slab"},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_stairs"},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_bricks"},{"id":"minecraft:prismarine_crystals","localizedName":"Prismarine Crystals","maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_crystals"},{"id":"minecraft:prismarine_shard","localizedName":"Prismarine Shard","maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_shard"},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_slab"},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_stairs"},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_wall"},{"id":"minecraft:prize_pottery_sherd","localizedName":"Prize Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.prize_pottery_sherd"},{"id":"minecraft:pufferfish","localizedName":"Pufferfish","maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish"},{"id":"minecraft:pufferfish_bucket","localizedName":"Bucket of Pufferfish","maxStackSize":1,"unlocalizedName":"item.minecraft.pufferfish_bucket"},{"id":"minecraft:pufferfish_spawn_egg","localizedName":"Pufferfish Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish_spawn_egg"},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","maxStackSize":64,"unlocalizedName":"block.minecraft.pumpkin"},{"id":"minecraft:pumpkin_pie","localizedName":"Pumpkin Pie","maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_pie"},{"id":"minecraft:pumpkin_seeds","localizedName":"Pumpkin Seeds","maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_seeds"},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.purple_banner"},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.purple_bed"},{"id":"minecraft:purple_candle","localizedName":"Purple Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_candle"},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_carpet"},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete"},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete_powder"},{"id":"minecraft:purple_dye","localizedName":"Purple Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.purple_dye"},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_glazed_terracotta"},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.purple_shulker_box"},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass"},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass_pane"},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_terracotta"},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_wool"},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_block"},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_pillar"},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_slab"},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_stairs"},{"id":"minecraft:quartz","localizedName":"Nether Quartz","maxStackSize":64,"unlocalizedName":"item.minecraft.quartz"},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_block"},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_bricks"},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_pillar"},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_slab"},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_stairs"},{"id":"minecraft:rabbit","localizedName":"Raw Rabbit","maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit"},{"id":"minecraft:rabbit_foot","localizedName":"Rabbit\u0027s Foot","maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_foot"},{"id":"minecraft:rabbit_hide","localizedName":"Rabbit Hide","maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_hide"},{"id":"minecraft:rabbit_spawn_egg","localizedName":"Rabbit Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_spawn_egg"},{"id":"minecraft:rabbit_stew","localizedName":"Rabbit Stew","maxStackSize":1,"unlocalizedName":"item.minecraft.rabbit_stew"},{"id":"minecraft:rail","localizedName":"Rail","maxStackSize":64,"unlocalizedName":"block.minecraft.rail"},{"id":"minecraft:raiser_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.raiser_armor_trim_smithing_template"},{"id":"minecraft:ravager_spawn_egg","localizedName":"Ravager Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.ravager_spawn_egg"},{"id":"minecraft:raw_copper","localizedName":"Raw Copper","maxStackSize":64,"unlocalizedName":"item.minecraft.raw_copper"},{"id":"minecraft:raw_copper_block","localizedName":"Block of Raw Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.raw_copper_block"},{"id":"minecraft:raw_gold","localizedName":"Raw Gold","maxStackSize":64,"unlocalizedName":"item.minecraft.raw_gold"},{"id":"minecraft:raw_gold_block","localizedName":"Block of Raw Gold","maxStackSize":64,"unlocalizedName":"block.minecraft.raw_gold_block"},{"id":"minecraft:raw_iron","localizedName":"Raw Iron","maxStackSize":64,"unlocalizedName":"item.minecraft.raw_iron"},{"id":"minecraft:raw_iron_block","localizedName":"Block of Raw Iron","maxStackSize":64,"unlocalizedName":"block.minecraft.raw_iron_block"},{"id":"minecraft:recovery_compass","localizedName":"Recovery Compass","maxStackSize":64,"unlocalizedName":"item.minecraft.recovery_compass"},{"id":"minecraft:red_banner","localizedName":"Red Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.red_banner"},{"id":"minecraft:red_bed","localizedName":"Red Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.red_bed"},{"id":"minecraft:red_candle","localizedName":"Red Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.red_candle"},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.red_carpet"},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete"},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete_powder"},{"id":"minecraft:red_dye","localizedName":"Red Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.red_dye"},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.red_glazed_terracotta"},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom"},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom_block"},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_slab"},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_stairs"},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_wall"},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_bricks"},{"id":"minecraft:red_sand","localizedName":"Red Sand","maxStackSize":64,"unlocalizedName":"block.minecraft.red_sand"},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone"},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_slab"},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_stairs"},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_wall"},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.red_shulker_box"},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass"},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass_pane"},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.red_terracotta"},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","maxStackSize":64,"unlocalizedName":"block.minecraft.red_tulip"},{"id":"minecraft:red_wool","localizedName":"Red Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.red_wool"},{"id":"minecraft:redstone","localizedName":"Redstone Dust","maxStackSize":64,"unlocalizedName":"item.minecraft.redstone"},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_block"},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_lamp"},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_ore"},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_torch"},{"id":"minecraft:reinforced_deepslate","localizedName":"Reinforced Deepslate","maxStackSize":64,"unlocalizedName":"block.minecraft.reinforced_deepslate"},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","maxStackSize":64,"unlocalizedName":"block.minecraft.repeater"},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","maxStackSize":64,"unlocalizedName":"block.minecraft.repeating_command_block"},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","maxStackSize":64,"unlocalizedName":"block.minecraft.respawn_anchor"},{"id":"minecraft:rib_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.rib_armor_trim_smithing_template"},{"id":"minecraft:rooted_dirt","localizedName":"Rooted Dirt","maxStackSize":64,"unlocalizedName":"block.minecraft.rooted_dirt"},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","maxStackSize":64,"unlocalizedName":"block.minecraft.rose_bush"},{"id":"minecraft:rotten_flesh","localizedName":"Rotten Flesh","maxStackSize":64,"unlocalizedName":"item.minecraft.rotten_flesh"},{"id":"minecraft:saddle","localizedName":"Saddle","maxStackSize":1,"unlocalizedName":"item.minecraft.saddle"},{"id":"minecraft:salmon","localizedName":"Raw Salmon","maxStackSize":64,"unlocalizedName":"item.minecraft.salmon"},{"id":"minecraft:salmon_bucket","localizedName":"Bucket of Salmon","maxStackSize":1,"unlocalizedName":"item.minecraft.salmon_bucket"},{"id":"minecraft:salmon_spawn_egg","localizedName":"Salmon Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.salmon_spawn_egg"},{"id":"minecraft:sand","localizedName":"Sand","maxStackSize":64,"unlocalizedName":"block.minecraft.sand"},{"id":"minecraft:sandstone","localizedName":"Sandstone","maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone"},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_slab"},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_stairs"},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_wall"},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","maxStackSize":64,"unlocalizedName":"block.minecraft.scaffolding"},{"id":"minecraft:scrape_pottery_sherd","localizedName":"Scrape Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.scrape_pottery_sherd"},{"id":"minecraft:sculk","localizedName":"Sculk","maxStackSize":64,"unlocalizedName":"block.minecraft.sculk"},{"id":"minecraft:sculk_catalyst","localizedName":"Sculk Catalyst","maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_catalyst"},{"id":"minecraft:sculk_sensor","localizedName":"Sculk Sensor","maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_sensor"},{"id":"minecraft:sculk_shrieker","localizedName":"Sculk Shrieker","maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_shrieker"},{"id":"minecraft:sculk_vein","localizedName":"Sculk Vein","maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_vein"},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","maxStackSize":64,"unlocalizedName":"block.minecraft.sea_lantern"},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","maxStackSize":64,"unlocalizedName":"block.minecraft.sea_pickle"},{"id":"minecraft:seagrass","localizedName":"Seagrass","maxStackSize":64,"unlocalizedName":"block.minecraft.seagrass"},{"id":"minecraft:sentry_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.sentry_armor_trim_smithing_template"},{"id":"minecraft:shaper_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.shaper_armor_trim_smithing_template"},{"id":"minecraft:sheaf_pottery_sherd","localizedName":"Sheaf Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.sheaf_pottery_sherd"},{"id":"minecraft:shears","localizedName":"Shears","maxDamage":238,"maxStackSize":1,"unlocalizedName":"item.minecraft.shears"},{"id":"minecraft:sheep_spawn_egg","localizedName":"Sheep Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.sheep_spawn_egg"},{"id":"minecraft:shelter_pottery_sherd","localizedName":"Shelter Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.shelter_pottery_sherd"},{"id":"minecraft:shield","localizedName":"Shield","maxDamage":336,"maxStackSize":1,"unlocalizedName":"item.minecraft.shield"},{"id":"minecraft:short_grass","localizedName":"Short Grass","maxStackSize":64,"unlocalizedName":"block.minecraft.short_grass"},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","maxStackSize":64,"unlocalizedName":"block.minecraft.shroomlight"},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.shulker_box"},{"id":"minecraft:shulker_shell","localizedName":"Shulker Shell","maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_shell"},{"id":"minecraft:shulker_spawn_egg","localizedName":"Shulker Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_spawn_egg"},{"id":"minecraft:silence_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.silence_armor_trim_smithing_template"},{"id":"minecraft:silverfish_spawn_egg","localizedName":"Silverfish Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.silverfish_spawn_egg"},{"id":"minecraft:skeleton_horse_spawn_egg","localizedName":"Skeleton Horse Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_horse_spawn_egg"},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","maxStackSize":64,"unlocalizedName":"block.minecraft.skeleton_skull"},{"id":"minecraft:skeleton_spawn_egg","localizedName":"Skeleton Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_spawn_egg"},{"id":"minecraft:skull_banner_pattern","localizedName":"Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.skull_banner_pattern"},{"id":"minecraft:skull_pottery_sherd","localizedName":"Skull Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.skull_pottery_sherd"},{"id":"minecraft:slime_ball","localizedName":"Slimeball","maxStackSize":64,"unlocalizedName":"item.minecraft.slime_ball"},{"id":"minecraft:slime_block","localizedName":"Slime Block","maxStackSize":64,"unlocalizedName":"block.minecraft.slime_block"},{"id":"minecraft:slime_spawn_egg","localizedName":"Slime Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.slime_spawn_egg"},{"id":"minecraft:small_amethyst_bud","localizedName":"Small Amethyst Bud","maxStackSize":64,"unlocalizedName":"block.minecraft.small_amethyst_bud"},{"id":"minecraft:small_dripleaf","localizedName":"Small Dripleaf","maxStackSize":64,"unlocalizedName":"block.minecraft.small_dripleaf"},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","maxStackSize":64,"unlocalizedName":"block.minecraft.smithing_table"},{"id":"minecraft:smoker","localizedName":"Smoker","maxStackSize":64,"unlocalizedName":"block.minecraft.smoker"},{"id":"minecraft:smooth_basalt","localizedName":"Smooth Basalt","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_basalt"},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz"},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_slab"},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_stairs"},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone"},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_slab"},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_stairs"},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone"},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_slab"},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_stairs"},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone"},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone_slab"},{"id":"minecraft:sniffer_egg","localizedName":"Sniffer Egg","maxStackSize":64,"unlocalizedName":"block.minecraft.sniffer_egg"},{"id":"minecraft:sniffer_spawn_egg","localizedName":"Sniffer Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.sniffer_spawn_egg"},{"id":"minecraft:snort_pottery_sherd","localizedName":"Snort Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.snort_pottery_sherd"},{"id":"minecraft:snout_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.snout_armor_trim_smithing_template"},{"id":"minecraft:snow","localizedName":"Snow","maxStackSize":64,"unlocalizedName":"block.minecraft.snow"},{"id":"minecraft:snow_block","localizedName":"Snow Block","maxStackSize":64,"unlocalizedName":"block.minecraft.snow_block"},{"id":"minecraft:snow_golem_spawn_egg","localizedName":"Snow Golem Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.snow_golem_spawn_egg"},{"id":"minecraft:snowball","localizedName":"Snowball","maxStackSize":16,"unlocalizedName":"item.minecraft.snowball"},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","maxStackSize":64,"unlocalizedName":"block.minecraft.soul_campfire"},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","maxStackSize":64,"unlocalizedName":"block.minecraft.soul_lantern"},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","maxStackSize":64,"unlocalizedName":"block.minecraft.soul_sand"},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","maxStackSize":64,"unlocalizedName":"block.minecraft.soul_soil"},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","maxStackSize":64,"unlocalizedName":"block.minecraft.soul_torch"},{"id":"minecraft:spawner","localizedName":"Monster Spawner","maxStackSize":64,"unlocalizedName":"block.minecraft.spawner"},{"id":"minecraft:spectral_arrow","localizedName":"Spectral Arrow","maxStackSize":64,"unlocalizedName":"item.minecraft.spectral_arrow"},{"id":"minecraft:spider_eye","localizedName":"Spider Eye","maxStackSize":64,"unlocalizedName":"item.minecraft.spider_eye"},{"id":"minecraft:spider_spawn_egg","localizedName":"Spider Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.spider_spawn_egg"},{"id":"minecraft:spire_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.spire_armor_trim_smithing_template"},{"id":"minecraft:splash_potion","localizedName":"Splash Water Bottle","maxStackSize":1,"unlocalizedName":"item.minecraft.splash_potion.effect.water"},{"id":"minecraft:sponge","localizedName":"Sponge","maxStackSize":64,"unlocalizedName":"block.minecraft.sponge"},{"id":"minecraft:spore_blossom","localizedName":"Spore Blossom","maxStackSize":64,"unlocalizedName":"block.minecraft.spore_blossom"},{"id":"minecraft:spruce_boat","localizedName":"Spruce Boat","maxStackSize":1,"unlocalizedName":"item.minecraft.spruce_boat"},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_button"},{"id":"minecraft:spruce_chest_boat","localizedName":"Spruce Boat with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.spruce_chest_boat"},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_door"},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence"},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence_gate"},{"id":"minecraft:spruce_hanging_sign","localizedName":"Spruce Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.spruce_hanging_sign"},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_leaves"},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_log"},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_planks"},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_pressure_plate"},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_sapling"},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.spruce_sign"},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_slab"},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_stairs"},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_trapdoor"},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_wood"},{"id":"minecraft:spyglass","localizedName":"Spyglass","maxStackSize":1,"unlocalizedName":"item.minecraft.spyglass"},{"id":"minecraft:squid_spawn_egg","localizedName":"Squid Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.squid_spawn_egg"},{"id":"minecraft:stick","localizedName":"Stick","maxStackSize":64,"unlocalizedName":"item.minecraft.stick"},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","maxStackSize":64,"unlocalizedName":"block.minecraft.sticky_piston"},{"id":"minecraft:stone","localizedName":"Stone","maxStackSize":64,"unlocalizedName":"block.minecraft.stone"},{"id":"minecraft:stone_axe","localizedName":"Stone Axe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_axe"},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_slab"},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_stairs"},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_wall"},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.stone_bricks"},{"id":"minecraft:stone_button","localizedName":"Stone Button","maxStackSize":64,"unlocalizedName":"block.minecraft.stone_button"},{"id":"minecraft:stone_hoe","localizedName":"Stone Hoe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_hoe"},{"id":"minecraft:stone_pickaxe","localizedName":"Stone Pickaxe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_pickaxe"},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.stone_pressure_plate"},{"id":"minecraft:stone_shovel","localizedName":"Stone Shovel","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_shovel"},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.stone_slab"},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.stone_stairs"},{"id":"minecraft:stone_sword","localizedName":"Stone Sword","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_sword"},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","maxStackSize":64,"unlocalizedName":"block.minecraft.stonecutter"},{"id":"minecraft:stray_spawn_egg","localizedName":"Stray Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.stray_spawn_egg"},{"id":"minecraft:strider_spawn_egg","localizedName":"Strider Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.strider_spawn_egg"},{"id":"minecraft:string","localizedName":"String","maxStackSize":64,"unlocalizedName":"item.minecraft.string"},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_log"},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_wood"},{"id":"minecraft:stripped_bamboo_block","localizedName":"Block of Stripped Bamboo","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_bamboo_block"},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_log"},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_wood"},{"id":"minecraft:stripped_cherry_log","localizedName":"Stripped Cherry Log","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_cherry_log"},{"id":"minecraft:stripped_cherry_wood","localizedName":"Stripped Cherry Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_cherry_wood"},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_hyphae"},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_stem"},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_log"},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_wood"},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_log"},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_wood"},{"id":"minecraft:stripped_mangrove_log","localizedName":"Stripped Mangrove Log","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_mangrove_log"},{"id":"minecraft:stripped_mangrove_wood","localizedName":"Stripped Mangrove Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_mangrove_wood"},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_log"},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_wood"},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_log"},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_wood"},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_hyphae"},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_stem"},{"id":"minecraft:structure_block","localizedName":"Structure Block","maxStackSize":64,"unlocalizedName":"block.minecraft.structure_block"},{"id":"minecraft:structure_void","localizedName":"Structure Void","maxStackSize":64,"unlocalizedName":"block.minecraft.structure_void"},{"id":"minecraft:sugar","localizedName":"Sugar","maxStackSize":64,"unlocalizedName":"item.minecraft.sugar"},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","maxStackSize":64,"unlocalizedName":"block.minecraft.sugar_cane"},{"id":"minecraft:sunflower","localizedName":"Sunflower","maxStackSize":64,"unlocalizedName":"block.minecraft.sunflower"},{"id":"minecraft:suspicious_gravel","localizedName":"Suspicious Gravel","maxStackSize":64,"unlocalizedName":"block.minecraft.suspicious_gravel"},{"id":"minecraft:suspicious_sand","localizedName":"Suspicious Sand","maxStackSize":64,"unlocalizedName":"block.minecraft.suspicious_sand"},{"id":"minecraft:suspicious_stew","localizedName":"Suspicious Stew","maxStackSize":1,"unlocalizedName":"item.minecraft.suspicious_stew"},{"id":"minecraft:sweet_berries","localizedName":"Sweet Berries","maxStackSize":64,"unlocalizedName":"item.minecraft.sweet_berries"},{"id":"minecraft:tadpole_bucket","localizedName":"Bucket of Tadpole","maxStackSize":1,"unlocalizedName":"item.minecraft.tadpole_bucket"},{"id":"minecraft:tadpole_spawn_egg","localizedName":"Tadpole Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.tadpole_spawn_egg"},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","maxStackSize":64,"unlocalizedName":"block.minecraft.tall_grass"},{"id":"minecraft:target","localizedName":"Target","maxStackSize":64,"unlocalizedName":"block.minecraft.target"},{"id":"minecraft:terracotta","localizedName":"Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.terracotta"},{"id":"minecraft:tide_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.tide_armor_trim_smithing_template"},{"id":"minecraft:tinted_glass","localizedName":"Tinted Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.tinted_glass"},{"id":"minecraft:tipped_arrow","localizedName":"Arrow of Poison","maxStackSize":64,"unlocalizedName":"item.minecraft.tipped_arrow.effect.poison"},{"id":"minecraft:tnt","localizedName":"TNT","maxStackSize":64,"unlocalizedName":"block.minecraft.tnt"},{"id":"minecraft:tnt_minecart","localizedName":"Minecart with TNT","maxStackSize":1,"unlocalizedName":"item.minecraft.tnt_minecart"},{"id":"minecraft:torch","localizedName":"Torch","maxStackSize":64,"unlocalizedName":"block.minecraft.torch"},{"id":"minecraft:torchflower","localizedName":"Torchflower","maxStackSize":64,"unlocalizedName":"block.minecraft.torchflower"},{"id":"minecraft:torchflower_seeds","localizedName":"Torchflower Seeds","maxStackSize":64,"unlocalizedName":"item.minecraft.torchflower_seeds"},{"id":"minecraft:totem_of_undying","localizedName":"Totem of Undying","maxStackSize":1,"unlocalizedName":"item.minecraft.totem_of_undying"},{"id":"minecraft:trader_llama_spawn_egg","localizedName":"Trader Llama Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.trader_llama_spawn_egg"},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","maxStackSize":64,"unlocalizedName":"block.minecraft.trapped_chest"},{"id":"minecraft:trial_key","localizedName":"Trial Key","maxStackSize":64,"unlocalizedName":"item.minecraft.trial_key"},{"id":"minecraft:trial_spawner","localizedName":"Trial Spawner","maxStackSize":64,"unlocalizedName":"block.minecraft.trial_spawner"},{"id":"minecraft:trident","localizedName":"Trident","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.trident"},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","maxStackSize":64,"unlocalizedName":"block.minecraft.tripwire_hook"},{"id":"minecraft:tropical_fish","localizedName":"Tropical Fish","maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish"},{"id":"minecraft:tropical_fish_bucket","localizedName":"Bucket of Tropical Fish","maxStackSize":1,"unlocalizedName":"item.minecraft.tropical_fish_bucket"},{"id":"minecraft:tropical_fish_spawn_egg","localizedName":"Tropical Fish Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish_spawn_egg"},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral"},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_block"},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_fan"},{"id":"minecraft:tuff","localizedName":"Tuff","maxStackSize":64,"unlocalizedName":"block.minecraft.tuff"},{"id":"minecraft:tuff_brick_slab","localizedName":"Tuff Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.tuff_brick_slab"},{"id":"minecraft:tuff_brick_stairs","localizedName":"Tuff Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.tuff_brick_stairs"},{"id":"minecraft:tuff_brick_wall","localizedName":"Tuff Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.tuff_brick_wall"},{"id":"minecraft:tuff_bricks","localizedName":"Tuff Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.tuff_bricks"},{"id":"minecraft:tuff_slab","localizedName":"Tuff Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.tuff_slab"},{"id":"minecraft:tuff_stairs","localizedName":"Tuff Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.tuff_stairs"},{"id":"minecraft:tuff_wall","localizedName":"Tuff Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.tuff_wall"},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","maxStackSize":64,"unlocalizedName":"block.minecraft.turtle_egg"},{"id":"minecraft:turtle_helmet","localizedName":"Turtle Shell","maxDamage":275,"maxStackSize":1,"unlocalizedName":"item.minecraft.turtle_helmet"},{"id":"minecraft:turtle_scute","localizedName":"Turtle Scute","maxStackSize":64,"unlocalizedName":"item.minecraft.turtle_scute"},{"id":"minecraft:turtle_spawn_egg","localizedName":"Turtle Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.turtle_spawn_egg"},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","maxStackSize":64,"unlocalizedName":"block.minecraft.twisting_vines"},{"id":"minecraft:vault","localizedName":"Vault","maxStackSize":64,"unlocalizedName":"block.minecraft.vault"},{"id":"minecraft:verdant_froglight","localizedName":"Verdant Froglight","maxStackSize":64,"unlocalizedName":"block.minecraft.verdant_froglight"},{"id":"minecraft:vex_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.vex_armor_trim_smithing_template"},{"id":"minecraft:vex_spawn_egg","localizedName":"Vex Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.vex_spawn_egg"},{"id":"minecraft:villager_spawn_egg","localizedName":"Villager Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.villager_spawn_egg"},{"id":"minecraft:vindicator_spawn_egg","localizedName":"Vindicator Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.vindicator_spawn_egg"},{"id":"minecraft:vine","localizedName":"Vines","maxStackSize":64,"unlocalizedName":"block.minecraft.vine"},{"id":"minecraft:wandering_trader_spawn_egg","localizedName":"Wandering Trader Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.wandering_trader_spawn_egg"},{"id":"minecraft:ward_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.ward_armor_trim_smithing_template"},{"id":"minecraft:warden_spawn_egg","localizedName":"Warden Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.warden_spawn_egg"},{"id":"minecraft:warped_button","localizedName":"Warped Button","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_button"},{"id":"minecraft:warped_door","localizedName":"Warped Door","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_door"},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence"},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence_gate"},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fungus"},{"id":"minecraft:warped_fungus_on_a_stick","localizedName":"Warped Fungus on a Stick","maxDamage":100,"maxStackSize":1,"unlocalizedName":"item.minecraft.warped_fungus_on_a_stick"},{"id":"minecraft:warped_hanging_sign","localizedName":"Warped Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.warped_hanging_sign"},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_hyphae"},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_nylium"},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_planks"},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_pressure_plate"},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_roots"},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.warped_sign"},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_slab"},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stairs"},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stem"},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_trapdoor"},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_wart_block"},{"id":"minecraft:water_bucket","localizedName":"Water Bucket","maxStackSize":1,"unlocalizedName":"item.minecraft.water_bucket"},{"id":"minecraft:waxed_chiseled_copper","localizedName":"Waxed Chiseled Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_chiseled_copper"},{"id":"minecraft:waxed_copper_block","localizedName":"Waxed Block of Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_copper_block"},{"id":"minecraft:waxed_copper_bulb","localizedName":"Waxed Copper Bulb","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_copper_bulb"},{"id":"minecraft:waxed_copper_door","localizedName":"Waxed Copper Door","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_copper_door"},{"id":"minecraft:waxed_copper_grate","localizedName":"Waxed Copper Grate","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_copper_grate"},{"id":"minecraft:waxed_copper_trapdoor","localizedName":"Waxed Copper Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_copper_trapdoor"},{"id":"minecraft:waxed_cut_copper","localizedName":"Waxed Cut Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper"},{"id":"minecraft:waxed_cut_copper_slab","localizedName":"Waxed Cut Copper Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper_slab"},{"id":"minecraft:waxed_cut_copper_stairs","localizedName":"Waxed Cut Copper Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper_stairs"},{"id":"minecraft:waxed_exposed_chiseled_copper","localizedName":"Waxed Exposed Chiseled Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_chiseled_copper"},{"id":"minecraft:waxed_exposed_copper","localizedName":"Waxed Exposed Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_copper"},{"id":"minecraft:waxed_exposed_copper_bulb","localizedName":"Waxed Exposed Copper Bulb","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_copper_bulb"},{"id":"minecraft:waxed_exposed_copper_door","localizedName":"Waxed Exposed Copper Door","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_copper_door"},{"id":"minecraft:waxed_exposed_copper_grate","localizedName":"Waxed Exposed Copper Grate","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_copper_grate"},{"id":"minecraft:waxed_exposed_copper_trapdoor","localizedName":"Waxed Exposed Copper Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_copper_trapdoor"},{"id":"minecraft:waxed_exposed_cut_copper","localizedName":"Waxed Exposed Cut Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper"},{"id":"minecraft:waxed_exposed_cut_copper_slab","localizedName":"Waxed Exposed Cut Copper Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper_slab"},{"id":"minecraft:waxed_exposed_cut_copper_stairs","localizedName":"Waxed Exposed Cut Copper Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper_stairs"},{"id":"minecraft:waxed_oxidized_chiseled_copper","localizedName":"Waxed Oxidized Chiseled Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_chiseled_copper"},{"id":"minecraft:waxed_oxidized_copper","localizedName":"Waxed Oxidized Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_copper"},{"id":"minecraft:waxed_oxidized_copper_bulb","localizedName":"Waxed Oxidized Copper Bulb","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_copper_bulb"},{"id":"minecraft:waxed_oxidized_copper_door","localizedName":"Waxed Oxidized Copper Door","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_copper_door"},{"id":"minecraft:waxed_oxidized_copper_grate","localizedName":"Waxed Oxidized Copper Grate","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_copper_grate"},{"id":"minecraft:waxed_oxidized_copper_trapdoor","localizedName":"Waxed Oxidized Copper Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_copper_trapdoor"},{"id":"minecraft:waxed_oxidized_cut_copper","localizedName":"Waxed Oxidized Cut Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper"},{"id":"minecraft:waxed_oxidized_cut_copper_slab","localizedName":"Waxed Oxidized Cut Copper Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper_slab"},{"id":"minecraft:waxed_oxidized_cut_copper_stairs","localizedName":"Waxed Oxidized Cut Copper Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper_stairs"},{"id":"minecraft:waxed_weathered_chiseled_copper","localizedName":"Waxed Weathered Chiseled Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_chiseled_copper"},{"id":"minecraft:waxed_weathered_copper","localizedName":"Waxed Weathered Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_copper"},{"id":"minecraft:waxed_weathered_copper_bulb","localizedName":"Waxed Weathered Copper Bulb","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_copper_bulb"},{"id":"minecraft:waxed_weathered_copper_door","localizedName":"Waxed Weathered Copper Door","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_copper_door"},{"id":"minecraft:waxed_weathered_copper_grate","localizedName":"Waxed Weathered Copper Grate","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_copper_grate"},{"id":"minecraft:waxed_weathered_copper_trapdoor","localizedName":"Waxed Weathered Copper Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_copper_trapdoor"},{"id":"minecraft:waxed_weathered_cut_copper","localizedName":"Waxed Weathered Cut Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper"},{"id":"minecraft:waxed_weathered_cut_copper_slab","localizedName":"Waxed Weathered Cut Copper Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper_slab"},{"id":"minecraft:waxed_weathered_cut_copper_stairs","localizedName":"Waxed Weathered Cut Copper Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper_stairs"},{"id":"minecraft:wayfinder_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.wayfinder_armor_trim_smithing_template"},{"id":"minecraft:weathered_chiseled_copper","localizedName":"Weathered Chiseled Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_chiseled_copper"},{"id":"minecraft:weathered_copper","localizedName":"Weathered Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_copper"},{"id":"minecraft:weathered_copper_bulb","localizedName":"Weathered Copper Bulb","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_copper_bulb"},{"id":"minecraft:weathered_copper_door","localizedName":"Weathered Copper Door","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_copper_door"},{"id":"minecraft:weathered_copper_grate","localizedName":"Weathered Copper Grate","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_copper_grate"},{"id":"minecraft:weathered_copper_trapdoor","localizedName":"Weathered Copper Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_copper_trapdoor"},{"id":"minecraft:weathered_cut_copper","localizedName":"Weathered Cut Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper"},{"id":"minecraft:weathered_cut_copper_slab","localizedName":"Weathered Cut Copper Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper_slab"},{"id":"minecraft:weathered_cut_copper_stairs","localizedName":"Weathered Cut Copper Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper_stairs"},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","maxStackSize":64,"unlocalizedName":"block.minecraft.weeping_vines"},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","maxStackSize":64,"unlocalizedName":"block.minecraft.wet_sponge"},{"id":"minecraft:wheat","localizedName":"Wheat","maxStackSize":64,"unlocalizedName":"item.minecraft.wheat"},{"id":"minecraft:wheat_seeds","localizedName":"Wheat Seeds","maxStackSize":64,"unlocalizedName":"item.minecraft.wheat_seeds"},{"id":"minecraft:white_banner","localizedName":"White Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.white_banner"},{"id":"minecraft:white_bed","localizedName":"White Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.white_bed"},{"id":"minecraft:white_candle","localizedName":"White Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.white_candle"},{"id":"minecraft:white_carpet","localizedName":"White Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.white_carpet"},{"id":"minecraft:white_concrete","localizedName":"White Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete"},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete_powder"},{"id":"minecraft:white_dye","localizedName":"White Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.white_dye"},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.white_glazed_terracotta"},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.white_shulker_box"},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass"},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass_pane"},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.white_terracotta"},{"id":"minecraft:white_tulip","localizedName":"White Tulip","maxStackSize":64,"unlocalizedName":"block.minecraft.white_tulip"},{"id":"minecraft:white_wool","localizedName":"White Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.white_wool"},{"id":"minecraft:wild_armor_trim_smithing_template","localizedName":"Smithing Template","maxStackSize":64,"unlocalizedName":"item.minecraft.wild_armor_trim_smithing_template"},{"id":"minecraft:wind_charge","localizedName":"Wind Charge","maxStackSize":64,"unlocalizedName":"item.minecraft.wind_charge"},{"id":"minecraft:witch_spawn_egg","localizedName":"Witch Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.witch_spawn_egg"},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","maxStackSize":64,"unlocalizedName":"block.minecraft.wither_rose"},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","maxStackSize":64,"unlocalizedName":"block.minecraft.wither_skeleton_skull"},{"id":"minecraft:wither_skeleton_spawn_egg","localizedName":"Wither Skeleton Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.wither_skeleton_spawn_egg"},{"id":"minecraft:wither_spawn_egg","localizedName":"Wither Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.wither_spawn_egg"},{"id":"minecraft:wolf_armor","localizedName":"Wolf Armor","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.wolf_armor"},{"id":"minecraft:wolf_spawn_egg","localizedName":"Wolf Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.wolf_spawn_egg"},{"id":"minecraft:wooden_axe","localizedName":"Wooden Axe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_axe"},{"id":"minecraft:wooden_hoe","localizedName":"Wooden Hoe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_hoe"},{"id":"minecraft:wooden_pickaxe","localizedName":"Wooden Pickaxe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_pickaxe"},{"id":"minecraft:wooden_shovel","localizedName":"Wooden Shovel","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_shovel"},{"id":"minecraft:wooden_sword","localizedName":"Wooden Sword","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_sword"},{"id":"minecraft:writable_book","localizedName":"Book and Quill","maxStackSize":1,"unlocalizedName":"item.minecraft.writable_book"},{"id":"minecraft:written_book","localizedName":"Written Book","maxStackSize":16,"unlocalizedName":"item.minecraft.written_book"},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.yellow_banner"},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_bed"},{"id":"minecraft:yellow_candle","localizedName":"Yellow Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_candle"},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_carpet"},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete"},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete_powder"},{"id":"minecraft:yellow_dye","localizedName":"Yellow Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.yellow_dye"},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_glazed_terracotta"},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_shulker_box"},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass"},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass_pane"},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_terracotta"},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_wool"},{"id":"minecraft:zoglin_spawn_egg","localizedName":"Zoglin Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.zoglin_spawn_egg"},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","maxStackSize":64,"unlocalizedName":"block.minecraft.zombie_head"},{"id":"minecraft:zombie_horse_spawn_egg","localizedName":"Zombie Horse Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_horse_spawn_egg"},{"id":"minecraft:zombie_spawn_egg","localizedName":"Zombie Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_spawn_egg"},{"id":"minecraft:zombie_villager_spawn_egg","localizedName":"Zombie Villager Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_villager_spawn_egg"},{"id":"minecraft:zombified_piglin_spawn_egg","localizedName":"Zombified Piglin Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.zombified_piglin_spawn_egg"}] \ No newline at end of file diff --git a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.1213.json b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.1213.json new file mode 100644 index 000000000..bfa6c7439 --- /dev/null +++ b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.1213.json @@ -0,0 +1 @@ +[{"id":"minecraft:acacia_boat","localizedName":"Acacia Boat","maxStackSize":1,"unlocalizedName":"item.minecraft.acacia_boat"},{"id":"minecraft:acacia_button","localizedName":"Acacia Button","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_button"},{"id":"minecraft:acacia_chest_boat","localizedName":"Acacia Boat with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.acacia_chest_boat"},{"id":"minecraft:acacia_door","localizedName":"Acacia Door","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_door"},{"id":"minecraft:acacia_fence","localizedName":"Acacia Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence"},{"id":"minecraft:acacia_fence_gate","localizedName":"Acacia Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_fence_gate"},{"id":"minecraft:acacia_hanging_sign","localizedName":"Acacia Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.acacia_hanging_sign"},{"id":"minecraft:acacia_leaves","localizedName":"Acacia Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_leaves"},{"id":"minecraft:acacia_log","localizedName":"Acacia Log","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_log"},{"id":"minecraft:acacia_planks","localizedName":"Acacia Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_planks"},{"id":"minecraft:acacia_pressure_plate","localizedName":"Acacia Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_pressure_plate"},{"id":"minecraft:acacia_sapling","localizedName":"Acacia Sapling","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_sapling"},{"id":"minecraft:acacia_sign","localizedName":"Acacia Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.acacia_sign"},{"id":"minecraft:acacia_slab","localizedName":"Acacia Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_slab"},{"id":"minecraft:acacia_stairs","localizedName":"Acacia Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_stairs"},{"id":"minecraft:acacia_trapdoor","localizedName":"Acacia Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_trapdoor"},{"id":"minecraft:acacia_wood","localizedName":"Acacia Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.acacia_wood"},{"id":"minecraft:activator_rail","localizedName":"Activator Rail","maxStackSize":64,"unlocalizedName":"block.minecraft.activator_rail"},{"id":"minecraft:air","localizedName":"Air","maxStackSize":64,"unlocalizedName":"block.minecraft.air"},{"id":"minecraft:allay_spawn_egg","localizedName":"Allay Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.allay_spawn_egg"},{"id":"minecraft:allium","localizedName":"Allium","maxStackSize":64,"unlocalizedName":"block.minecraft.allium"},{"id":"minecraft:amethyst_block","localizedName":"Block of Amethyst","maxStackSize":64,"unlocalizedName":"block.minecraft.amethyst_block"},{"id":"minecraft:amethyst_cluster","localizedName":"Amethyst Cluster","maxStackSize":64,"unlocalizedName":"block.minecraft.amethyst_cluster"},{"id":"minecraft:amethyst_shard","localizedName":"Amethyst Shard","maxStackSize":64,"unlocalizedName":"item.minecraft.amethyst_shard"},{"id":"minecraft:ancient_debris","localizedName":"Ancient Debris","maxStackSize":64,"unlocalizedName":"block.minecraft.ancient_debris"},{"id":"minecraft:andesite","localizedName":"Andesite","maxStackSize":64,"unlocalizedName":"block.minecraft.andesite"},{"id":"minecraft:andesite_slab","localizedName":"Andesite Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_slab"},{"id":"minecraft:andesite_stairs","localizedName":"Andesite Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_stairs"},{"id":"minecraft:andesite_wall","localizedName":"Andesite Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.andesite_wall"},{"id":"minecraft:angler_pottery_sherd","localizedName":"Angler Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.angler_pottery_sherd"},{"id":"minecraft:anvil","localizedName":"Anvil","maxStackSize":64,"unlocalizedName":"block.minecraft.anvil"},{"id":"minecraft:apple","localizedName":"Apple","maxStackSize":64,"unlocalizedName":"item.minecraft.apple"},{"id":"minecraft:archer_pottery_sherd","localizedName":"Archer Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.archer_pottery_sherd"},{"id":"minecraft:armadillo_scute","localizedName":"Armadillo Scute","maxStackSize":64,"unlocalizedName":"item.minecraft.armadillo_scute"},{"id":"minecraft:armadillo_spawn_egg","localizedName":"Armadillo Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.armadillo_spawn_egg"},{"id":"minecraft:armor_stand","localizedName":"Armor Stand","maxStackSize":16,"unlocalizedName":"item.minecraft.armor_stand"},{"id":"minecraft:arms_up_pottery_sherd","localizedName":"Arms Up Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.arms_up_pottery_sherd"},{"id":"minecraft:arrow","localizedName":"Arrow","maxStackSize":64,"unlocalizedName":"item.minecraft.arrow"},{"id":"minecraft:axolotl_bucket","localizedName":"Bucket of Axolotl","maxStackSize":1,"unlocalizedName":"item.minecraft.axolotl_bucket"},{"id":"minecraft:axolotl_spawn_egg","localizedName":"Axolotl Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.axolotl_spawn_egg"},{"id":"minecraft:azalea","localizedName":"Azalea","maxStackSize":64,"unlocalizedName":"block.minecraft.azalea"},{"id":"minecraft:azalea_leaves","localizedName":"Azalea Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.azalea_leaves"},{"id":"minecraft:azure_bluet","localizedName":"Azure Bluet","maxStackSize":64,"unlocalizedName":"block.minecraft.azure_bluet"},{"id":"minecraft:baked_potato","localizedName":"Baked Potato","maxStackSize":64,"unlocalizedName":"item.minecraft.baked_potato"},{"id":"minecraft:bamboo","localizedName":"Bamboo","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo"},{"id":"minecraft:bamboo_block","localizedName":"Block of Bamboo","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_block"},{"id":"minecraft:bamboo_button","localizedName":"Bamboo Button","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_button"},{"id":"minecraft:bamboo_chest_raft","localizedName":"Bamboo Raft with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.bamboo_chest_raft"},{"id":"minecraft:bamboo_door","localizedName":"Bamboo Door","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_door"},{"id":"minecraft:bamboo_fence","localizedName":"Bamboo Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_fence"},{"id":"minecraft:bamboo_fence_gate","localizedName":"Bamboo Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_fence_gate"},{"id":"minecraft:bamboo_hanging_sign","localizedName":"Bamboo Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.bamboo_hanging_sign"},{"id":"minecraft:bamboo_mosaic","localizedName":"Bamboo Mosaic","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_mosaic"},{"id":"minecraft:bamboo_mosaic_slab","localizedName":"Bamboo Mosaic Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_mosaic_slab"},{"id":"minecraft:bamboo_mosaic_stairs","localizedName":"Bamboo Mosaic Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_mosaic_stairs"},{"id":"minecraft:bamboo_planks","localizedName":"Bamboo Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_planks"},{"id":"minecraft:bamboo_pressure_plate","localizedName":"Bamboo Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_pressure_plate"},{"id":"minecraft:bamboo_raft","localizedName":"Bamboo Raft","maxStackSize":1,"unlocalizedName":"item.minecraft.bamboo_raft"},{"id":"minecraft:bamboo_sign","localizedName":"Bamboo Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.bamboo_sign"},{"id":"minecraft:bamboo_slab","localizedName":"Bamboo Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_slab"},{"id":"minecraft:bamboo_stairs","localizedName":"Bamboo Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_stairs"},{"id":"minecraft:bamboo_trapdoor","localizedName":"Bamboo Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.bamboo_trapdoor"},{"id":"minecraft:barrel","localizedName":"Barrel","maxStackSize":64,"unlocalizedName":"block.minecraft.barrel"},{"id":"minecraft:barrier","localizedName":"Barrier","maxStackSize":64,"unlocalizedName":"block.minecraft.barrier"},{"id":"minecraft:basalt","localizedName":"Basalt","maxStackSize":64,"unlocalizedName":"block.minecraft.basalt"},{"id":"minecraft:bat_spawn_egg","localizedName":"Bat Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.bat_spawn_egg"},{"id":"minecraft:beacon","localizedName":"Beacon","maxStackSize":64,"unlocalizedName":"block.minecraft.beacon"},{"id":"minecraft:bedrock","localizedName":"Bedrock","maxStackSize":64,"unlocalizedName":"block.minecraft.bedrock"},{"id":"minecraft:bee_nest","localizedName":"Bee Nest","maxStackSize":64,"unlocalizedName":"block.minecraft.bee_nest"},{"id":"minecraft:bee_spawn_egg","localizedName":"Bee Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.bee_spawn_egg"},{"id":"minecraft:beef","localizedName":"Raw Beef","maxStackSize":64,"unlocalizedName":"item.minecraft.beef"},{"id":"minecraft:beehive","localizedName":"Beehive","maxStackSize":64,"unlocalizedName":"block.minecraft.beehive"},{"id":"minecraft:beetroot","localizedName":"Beetroot","maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot"},{"id":"minecraft:beetroot_seeds","localizedName":"Beetroot Seeds","maxStackSize":64,"unlocalizedName":"item.minecraft.beetroot_seeds"},{"id":"minecraft:beetroot_soup","localizedName":"Beetroot Soup","maxStackSize":1,"unlocalizedName":"item.minecraft.beetroot_soup"},{"id":"minecraft:bell","localizedName":"Bell","maxStackSize":64,"unlocalizedName":"block.minecraft.bell"},{"id":"minecraft:big_dripleaf","localizedName":"Big Dripleaf","maxStackSize":64,"unlocalizedName":"block.minecraft.big_dripleaf"},{"id":"minecraft:birch_boat","localizedName":"Birch Boat","maxStackSize":1,"unlocalizedName":"item.minecraft.birch_boat"},{"id":"minecraft:birch_button","localizedName":"Birch Button","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_button"},{"id":"minecraft:birch_chest_boat","localizedName":"Birch Boat with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.birch_chest_boat"},{"id":"minecraft:birch_door","localizedName":"Birch Door","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_door"},{"id":"minecraft:birch_fence","localizedName":"Birch Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence"},{"id":"minecraft:birch_fence_gate","localizedName":"Birch Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_fence_gate"},{"id":"minecraft:birch_hanging_sign","localizedName":"Birch Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.birch_hanging_sign"},{"id":"minecraft:birch_leaves","localizedName":"Birch Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_leaves"},{"id":"minecraft:birch_log","localizedName":"Birch Log","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_log"},{"id":"minecraft:birch_planks","localizedName":"Birch Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_planks"},{"id":"minecraft:birch_pressure_plate","localizedName":"Birch Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_pressure_plate"},{"id":"minecraft:birch_sapling","localizedName":"Birch Sapling","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_sapling"},{"id":"minecraft:birch_sign","localizedName":"Birch Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.birch_sign"},{"id":"minecraft:birch_slab","localizedName":"Birch Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_slab"},{"id":"minecraft:birch_stairs","localizedName":"Birch Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_stairs"},{"id":"minecraft:birch_trapdoor","localizedName":"Birch Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_trapdoor"},{"id":"minecraft:birch_wood","localizedName":"Birch Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.birch_wood"},{"id":"minecraft:black_banner","localizedName":"Black Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.black_banner"},{"id":"minecraft:black_bed","localizedName":"Black Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.black_bed"},{"id":"minecraft:black_bundle","localizedName":"Black Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.black_bundle"},{"id":"minecraft:black_candle","localizedName":"Black Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.black_candle"},{"id":"minecraft:black_carpet","localizedName":"Black Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.black_carpet"},{"id":"minecraft:black_concrete","localizedName":"Black Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete"},{"id":"minecraft:black_concrete_powder","localizedName":"Black Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.black_concrete_powder"},{"id":"minecraft:black_dye","localizedName":"Black Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.black_dye"},{"id":"minecraft:black_glazed_terracotta","localizedName":"Black Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.black_glazed_terracotta"},{"id":"minecraft:black_shulker_box","localizedName":"Black Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.black_shulker_box"},{"id":"minecraft:black_stained_glass","localizedName":"Black Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass"},{"id":"minecraft:black_stained_glass_pane","localizedName":"Black Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.black_stained_glass_pane"},{"id":"minecraft:black_terracotta","localizedName":"Black Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.black_terracotta"},{"id":"minecraft:black_wool","localizedName":"Black Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.black_wool"},{"id":"minecraft:blackstone","localizedName":"Blackstone","maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone"},{"id":"minecraft:blackstone_slab","localizedName":"Blackstone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_slab"},{"id":"minecraft:blackstone_stairs","localizedName":"Blackstone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_stairs"},{"id":"minecraft:blackstone_wall","localizedName":"Blackstone Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.blackstone_wall"},{"id":"minecraft:blade_pottery_sherd","localizedName":"Blade Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.blade_pottery_sherd"},{"id":"minecraft:blast_furnace","localizedName":"Blast Furnace","maxStackSize":64,"unlocalizedName":"block.minecraft.blast_furnace"},{"id":"minecraft:blaze_powder","localizedName":"Blaze Powder","maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_powder"},{"id":"minecraft:blaze_rod","localizedName":"Blaze Rod","maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_rod"},{"id":"minecraft:blaze_spawn_egg","localizedName":"Blaze Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.blaze_spawn_egg"},{"id":"minecraft:blue_banner","localizedName":"Blue Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.blue_banner"},{"id":"minecraft:blue_bed","localizedName":"Blue Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.blue_bed"},{"id":"minecraft:blue_bundle","localizedName":"Blue Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.blue_bundle"},{"id":"minecraft:blue_candle","localizedName":"Blue Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_candle"},{"id":"minecraft:blue_carpet","localizedName":"Blue Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_carpet"},{"id":"minecraft:blue_concrete","localizedName":"Blue Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete"},{"id":"minecraft:blue_concrete_powder","localizedName":"Blue Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_concrete_powder"},{"id":"minecraft:blue_dye","localizedName":"Blue Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.blue_dye"},{"id":"minecraft:blue_glazed_terracotta","localizedName":"Blue Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_glazed_terracotta"},{"id":"minecraft:blue_ice","localizedName":"Blue Ice","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_ice"},{"id":"minecraft:blue_orchid","localizedName":"Blue Orchid","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_orchid"},{"id":"minecraft:blue_shulker_box","localizedName":"Blue Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.blue_shulker_box"},{"id":"minecraft:blue_stained_glass","localizedName":"Blue Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass"},{"id":"minecraft:blue_stained_glass_pane","localizedName":"Blue Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_stained_glass_pane"},{"id":"minecraft:blue_terracotta","localizedName":"Blue Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_terracotta"},{"id":"minecraft:blue_wool","localizedName":"Blue Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.blue_wool"},{"id":"minecraft:bogged_spawn_egg","localizedName":"Bogged Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.bogged_spawn_egg"},{"id":"minecraft:bolt_armor_trim_smithing_template","localizedName":"Bolt Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.bolt_armor_trim_smithing_template"},{"id":"minecraft:bone","localizedName":"Bone","maxStackSize":64,"unlocalizedName":"item.minecraft.bone"},{"id":"minecraft:bone_block","localizedName":"Bone Block","maxStackSize":64,"unlocalizedName":"block.minecraft.bone_block"},{"id":"minecraft:bone_meal","localizedName":"Bone Meal","maxStackSize":64,"unlocalizedName":"item.minecraft.bone_meal"},{"id":"minecraft:book","localizedName":"Book","maxStackSize":64,"unlocalizedName":"item.minecraft.book"},{"id":"minecraft:bookshelf","localizedName":"Bookshelf","maxStackSize":64,"unlocalizedName":"block.minecraft.bookshelf"},{"id":"minecraft:bordure_indented_banner_pattern","localizedName":"Bordure Indented Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.bordure_indented_banner_pattern"},{"id":"minecraft:bow","localizedName":"Bow","maxDamage":384,"maxStackSize":1,"unlocalizedName":"item.minecraft.bow"},{"id":"minecraft:bowl","localizedName":"Bowl","maxStackSize":64,"unlocalizedName":"item.minecraft.bowl"},{"id":"minecraft:brain_coral","localizedName":"Brain Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral"},{"id":"minecraft:brain_coral_block","localizedName":"Brain Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_block"},{"id":"minecraft:brain_coral_fan","localizedName":"Brain Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.brain_coral_fan"},{"id":"minecraft:bread","localizedName":"Bread","maxStackSize":64,"unlocalizedName":"item.minecraft.bread"},{"id":"minecraft:breeze_rod","localizedName":"Breeze Rod","maxStackSize":64,"unlocalizedName":"item.minecraft.breeze_rod"},{"id":"minecraft:breeze_spawn_egg","localizedName":"Breeze Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.breeze_spawn_egg"},{"id":"minecraft:brewer_pottery_sherd","localizedName":"Brewer Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.brewer_pottery_sherd"},{"id":"minecraft:brewing_stand","localizedName":"Brewing Stand","maxStackSize":64,"unlocalizedName":"block.minecraft.brewing_stand"},{"id":"minecraft:brick","localizedName":"Brick","maxStackSize":64,"unlocalizedName":"item.minecraft.brick"},{"id":"minecraft:brick_slab","localizedName":"Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.brick_slab"},{"id":"minecraft:brick_stairs","localizedName":"Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.brick_stairs"},{"id":"minecraft:brick_wall","localizedName":"Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.brick_wall"},{"id":"minecraft:bricks","localizedName":"Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.bricks"},{"id":"minecraft:brown_banner","localizedName":"Brown Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.brown_banner"},{"id":"minecraft:brown_bed","localizedName":"Brown Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.brown_bed"},{"id":"minecraft:brown_bundle","localizedName":"Brown Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.brown_bundle"},{"id":"minecraft:brown_candle","localizedName":"Brown Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_candle"},{"id":"minecraft:brown_carpet","localizedName":"Brown Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_carpet"},{"id":"minecraft:brown_concrete","localizedName":"Brown Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete"},{"id":"minecraft:brown_concrete_powder","localizedName":"Brown Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_concrete_powder"},{"id":"minecraft:brown_dye","localizedName":"Brown Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.brown_dye"},{"id":"minecraft:brown_glazed_terracotta","localizedName":"Brown Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_glazed_terracotta"},{"id":"minecraft:brown_mushroom","localizedName":"Brown Mushroom","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom"},{"id":"minecraft:brown_mushroom_block","localizedName":"Brown Mushroom Block","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_mushroom_block"},{"id":"minecraft:brown_shulker_box","localizedName":"Brown Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.brown_shulker_box"},{"id":"minecraft:brown_stained_glass","localizedName":"Brown Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass"},{"id":"minecraft:brown_stained_glass_pane","localizedName":"Brown Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_stained_glass_pane"},{"id":"minecraft:brown_terracotta","localizedName":"Brown Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_terracotta"},{"id":"minecraft:brown_wool","localizedName":"Brown Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.brown_wool"},{"id":"minecraft:brush","localizedName":"Brush","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.brush"},{"id":"minecraft:bubble_coral","localizedName":"Bubble Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral"},{"id":"minecraft:bubble_coral_block","localizedName":"Bubble Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_block"},{"id":"minecraft:bubble_coral_fan","localizedName":"Bubble Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.bubble_coral_fan"},{"id":"minecraft:bucket","localizedName":"Bucket","maxStackSize":16,"unlocalizedName":"item.minecraft.bucket"},{"id":"minecraft:budding_amethyst","localizedName":"Budding Amethyst","maxStackSize":64,"unlocalizedName":"block.minecraft.budding_amethyst"},{"id":"minecraft:bundle","localizedName":"Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.bundle"},{"id":"minecraft:burn_pottery_sherd","localizedName":"Burn Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.burn_pottery_sherd"},{"id":"minecraft:cactus","localizedName":"Cactus","maxStackSize":64,"unlocalizedName":"block.minecraft.cactus"},{"id":"minecraft:cake","localizedName":"Cake","maxStackSize":1,"unlocalizedName":"block.minecraft.cake"},{"id":"minecraft:calcite","localizedName":"Calcite","maxStackSize":64,"unlocalizedName":"block.minecraft.calcite"},{"id":"minecraft:calibrated_sculk_sensor","localizedName":"Calibrated Sculk Sensor","maxStackSize":64,"unlocalizedName":"block.minecraft.calibrated_sculk_sensor"},{"id":"minecraft:camel_spawn_egg","localizedName":"Camel Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.camel_spawn_egg"},{"id":"minecraft:campfire","localizedName":"Campfire","maxStackSize":64,"unlocalizedName":"block.minecraft.campfire"},{"id":"minecraft:candle","localizedName":"Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.candle"},{"id":"minecraft:carrot","localizedName":"Carrot","maxStackSize":64,"unlocalizedName":"item.minecraft.carrot"},{"id":"minecraft:carrot_on_a_stick","localizedName":"Carrot on a Stick","maxDamage":25,"maxStackSize":1,"unlocalizedName":"item.minecraft.carrot_on_a_stick"},{"id":"minecraft:cartography_table","localizedName":"Cartography Table","maxStackSize":64,"unlocalizedName":"block.minecraft.cartography_table"},{"id":"minecraft:carved_pumpkin","localizedName":"Carved Pumpkin","maxStackSize":64,"unlocalizedName":"block.minecraft.carved_pumpkin"},{"id":"minecraft:cat_spawn_egg","localizedName":"Cat Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.cat_spawn_egg"},{"id":"minecraft:cauldron","localizedName":"Cauldron","maxStackSize":64,"unlocalizedName":"block.minecraft.cauldron"},{"id":"minecraft:cave_spider_spawn_egg","localizedName":"Cave Spider Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.cave_spider_spawn_egg"},{"id":"minecraft:chain","localizedName":"Chain","maxStackSize":64,"unlocalizedName":"block.minecraft.chain"},{"id":"minecraft:chain_command_block","localizedName":"Chain Command Block","maxStackSize":64,"unlocalizedName":"block.minecraft.chain_command_block"},{"id":"minecraft:chainmail_boots","localizedName":"Chainmail Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_boots"},{"id":"minecraft:chainmail_chestplate","localizedName":"Chainmail Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_chestplate"},{"id":"minecraft:chainmail_helmet","localizedName":"Chainmail Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_helmet"},{"id":"minecraft:chainmail_leggings","localizedName":"Chainmail Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.chainmail_leggings"},{"id":"minecraft:charcoal","localizedName":"Charcoal","maxStackSize":64,"unlocalizedName":"item.minecraft.charcoal"},{"id":"minecraft:cherry_boat","localizedName":"Cherry Boat","maxStackSize":1,"unlocalizedName":"item.minecraft.cherry_boat"},{"id":"minecraft:cherry_button","localizedName":"Cherry Button","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_button"},{"id":"minecraft:cherry_chest_boat","localizedName":"Cherry Boat with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.cherry_chest_boat"},{"id":"minecraft:cherry_door","localizedName":"Cherry Door","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_door"},{"id":"minecraft:cherry_fence","localizedName":"Cherry Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_fence"},{"id":"minecraft:cherry_fence_gate","localizedName":"Cherry Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_fence_gate"},{"id":"minecraft:cherry_hanging_sign","localizedName":"Cherry Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.cherry_hanging_sign"},{"id":"minecraft:cherry_leaves","localizedName":"Cherry Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_leaves"},{"id":"minecraft:cherry_log","localizedName":"Cherry Log","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_log"},{"id":"minecraft:cherry_planks","localizedName":"Cherry Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_planks"},{"id":"minecraft:cherry_pressure_plate","localizedName":"Cherry Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_pressure_plate"},{"id":"minecraft:cherry_sapling","localizedName":"Cherry Sapling","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_sapling"},{"id":"minecraft:cherry_sign","localizedName":"Cherry Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.cherry_sign"},{"id":"minecraft:cherry_slab","localizedName":"Cherry Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_slab"},{"id":"minecraft:cherry_stairs","localizedName":"Cherry Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_stairs"},{"id":"minecraft:cherry_trapdoor","localizedName":"Cherry Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_trapdoor"},{"id":"minecraft:cherry_wood","localizedName":"Cherry Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.cherry_wood"},{"id":"minecraft:chest","localizedName":"Chest","maxStackSize":64,"unlocalizedName":"block.minecraft.chest"},{"id":"minecraft:chest_minecart","localizedName":"Minecart with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.chest_minecart"},{"id":"minecraft:chicken","localizedName":"Raw Chicken","maxStackSize":64,"unlocalizedName":"item.minecraft.chicken"},{"id":"minecraft:chicken_spawn_egg","localizedName":"Chicken Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.chicken_spawn_egg"},{"id":"minecraft:chipped_anvil","localizedName":"Chipped Anvil","maxStackSize":64,"unlocalizedName":"block.minecraft.chipped_anvil"},{"id":"minecraft:chiseled_bookshelf","localizedName":"Chiseled Bookshelf","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_bookshelf"},{"id":"minecraft:chiseled_copper","localizedName":"Chiseled Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_copper"},{"id":"minecraft:chiseled_deepslate","localizedName":"Chiseled Deepslate","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_deepslate"},{"id":"minecraft:chiseled_nether_bricks","localizedName":"Chiseled Nether Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_nether_bricks"},{"id":"minecraft:chiseled_polished_blackstone","localizedName":"Chiseled Polished Blackstone","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_polished_blackstone"},{"id":"minecraft:chiseled_quartz_block","localizedName":"Chiseled Quartz Block","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_quartz_block"},{"id":"minecraft:chiseled_red_sandstone","localizedName":"Chiseled Red Sandstone","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_red_sandstone"},{"id":"minecraft:chiseled_sandstone","localizedName":"Chiseled Sandstone","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_sandstone"},{"id":"minecraft:chiseled_stone_bricks","localizedName":"Chiseled Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_stone_bricks"},{"id":"minecraft:chiseled_tuff","localizedName":"Chiseled Tuff","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_tuff"},{"id":"minecraft:chiseled_tuff_bricks","localizedName":"Chiseled Tuff Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.chiseled_tuff_bricks"},{"id":"minecraft:chorus_flower","localizedName":"Chorus Flower","maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_flower"},{"id":"minecraft:chorus_fruit","localizedName":"Chorus Fruit","maxStackSize":64,"unlocalizedName":"item.minecraft.chorus_fruit"},{"id":"minecraft:chorus_plant","localizedName":"Chorus Plant","maxStackSize":64,"unlocalizedName":"block.minecraft.chorus_plant"},{"id":"minecraft:clay","localizedName":"Clay","maxStackSize":64,"unlocalizedName":"block.minecraft.clay"},{"id":"minecraft:clay_ball","localizedName":"Clay Ball","maxStackSize":64,"unlocalizedName":"item.minecraft.clay_ball"},{"id":"minecraft:clock","localizedName":"Clock","maxStackSize":64,"unlocalizedName":"item.minecraft.clock"},{"id":"minecraft:coal","localizedName":"Coal","maxStackSize":64,"unlocalizedName":"item.minecraft.coal"},{"id":"minecraft:coal_block","localizedName":"Block of Coal","maxStackSize":64,"unlocalizedName":"block.minecraft.coal_block"},{"id":"minecraft:coal_ore","localizedName":"Coal Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.coal_ore"},{"id":"minecraft:coarse_dirt","localizedName":"Coarse Dirt","maxStackSize":64,"unlocalizedName":"block.minecraft.coarse_dirt"},{"id":"minecraft:coast_armor_trim_smithing_template","localizedName":"Coast Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.coast_armor_trim_smithing_template"},{"id":"minecraft:cobbled_deepslate","localizedName":"Cobbled Deepslate","maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate"},{"id":"minecraft:cobbled_deepslate_slab","localizedName":"Cobbled Deepslate Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_slab"},{"id":"minecraft:cobbled_deepslate_stairs","localizedName":"Cobbled Deepslate Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_stairs"},{"id":"minecraft:cobbled_deepslate_wall","localizedName":"Cobbled Deepslate Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.cobbled_deepslate_wall"},{"id":"minecraft:cobblestone","localizedName":"Cobblestone","maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone"},{"id":"minecraft:cobblestone_slab","localizedName":"Cobblestone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_slab"},{"id":"minecraft:cobblestone_stairs","localizedName":"Cobblestone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_stairs"},{"id":"minecraft:cobblestone_wall","localizedName":"Cobblestone Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.cobblestone_wall"},{"id":"minecraft:cobweb","localizedName":"Cobweb","maxStackSize":64,"unlocalizedName":"block.minecraft.cobweb"},{"id":"minecraft:cocoa_beans","localizedName":"Cocoa Beans","maxStackSize":64,"unlocalizedName":"item.minecraft.cocoa_beans"},{"id":"minecraft:cod","localizedName":"Raw Cod","maxStackSize":64,"unlocalizedName":"item.minecraft.cod"},{"id":"minecraft:cod_bucket","localizedName":"Bucket of Cod","maxStackSize":1,"unlocalizedName":"item.minecraft.cod_bucket"},{"id":"minecraft:cod_spawn_egg","localizedName":"Cod Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.cod_spawn_egg"},{"id":"minecraft:command_block","localizedName":"Command Block","maxStackSize":64,"unlocalizedName":"block.minecraft.command_block"},{"id":"minecraft:command_block_minecart","localizedName":"Minecart with Command Block","maxStackSize":1,"unlocalizedName":"item.minecraft.command_block_minecart"},{"id":"minecraft:comparator","localizedName":"Redstone Comparator","maxStackSize":64,"unlocalizedName":"block.minecraft.comparator"},{"id":"minecraft:compass","localizedName":"Compass","maxStackSize":64,"unlocalizedName":"item.minecraft.compass"},{"id":"minecraft:composter","localizedName":"Composter","maxStackSize":64,"unlocalizedName":"block.minecraft.composter"},{"id":"minecraft:conduit","localizedName":"Conduit","maxStackSize":64,"unlocalizedName":"block.minecraft.conduit"},{"id":"minecraft:cooked_beef","localizedName":"Steak","maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_beef"},{"id":"minecraft:cooked_chicken","localizedName":"Cooked Chicken","maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_chicken"},{"id":"minecraft:cooked_cod","localizedName":"Cooked Cod","maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_cod"},{"id":"minecraft:cooked_mutton","localizedName":"Cooked Mutton","maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_mutton"},{"id":"minecraft:cooked_porkchop","localizedName":"Cooked Porkchop","maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_porkchop"},{"id":"minecraft:cooked_rabbit","localizedName":"Cooked Rabbit","maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_rabbit"},{"id":"minecraft:cooked_salmon","localizedName":"Cooked Salmon","maxStackSize":64,"unlocalizedName":"item.minecraft.cooked_salmon"},{"id":"minecraft:cookie","localizedName":"Cookie","maxStackSize":64,"unlocalizedName":"item.minecraft.cookie"},{"id":"minecraft:copper_block","localizedName":"Block of Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.copper_block"},{"id":"minecraft:copper_bulb","localizedName":"Copper Bulb","maxStackSize":64,"unlocalizedName":"block.minecraft.copper_bulb"},{"id":"minecraft:copper_door","localizedName":"Copper Door","maxStackSize":64,"unlocalizedName":"block.minecraft.copper_door"},{"id":"minecraft:copper_grate","localizedName":"Copper Grate","maxStackSize":64,"unlocalizedName":"block.minecraft.copper_grate"},{"id":"minecraft:copper_ingot","localizedName":"Copper Ingot","maxStackSize":64,"unlocalizedName":"item.minecraft.copper_ingot"},{"id":"minecraft:copper_ore","localizedName":"Copper Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.copper_ore"},{"id":"minecraft:copper_trapdoor","localizedName":"Copper Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.copper_trapdoor"},{"id":"minecraft:cornflower","localizedName":"Cornflower","maxStackSize":64,"unlocalizedName":"block.minecraft.cornflower"},{"id":"minecraft:cow_spawn_egg","localizedName":"Cow Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.cow_spawn_egg"},{"id":"minecraft:cracked_deepslate_bricks","localizedName":"Cracked Deepslate Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_deepslate_bricks"},{"id":"minecraft:cracked_deepslate_tiles","localizedName":"Cracked Deepslate Tiles","maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_deepslate_tiles"},{"id":"minecraft:cracked_nether_bricks","localizedName":"Cracked Nether Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_nether_bricks"},{"id":"minecraft:cracked_polished_blackstone_bricks","localizedName":"Cracked Polished Blackstone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_polished_blackstone_bricks"},{"id":"minecraft:cracked_stone_bricks","localizedName":"Cracked Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.cracked_stone_bricks"},{"id":"minecraft:crafter","localizedName":"Crafter","maxStackSize":64,"unlocalizedName":"block.minecraft.crafter"},{"id":"minecraft:crafting_table","localizedName":"Crafting Table","maxStackSize":64,"unlocalizedName":"block.minecraft.crafting_table"},{"id":"minecraft:creaking_heart","localizedName":"Creaking Heart","maxStackSize":64,"unlocalizedName":"block.minecraft.creaking_heart"},{"id":"minecraft:creaking_spawn_egg","localizedName":"Creaking Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.creaking_spawn_egg"},{"id":"minecraft:creeper_banner_pattern","localizedName":"Creeper Charge Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.creeper_banner_pattern"},{"id":"minecraft:creeper_head","localizedName":"Creeper Head","maxStackSize":64,"unlocalizedName":"block.minecraft.creeper_head"},{"id":"minecraft:creeper_spawn_egg","localizedName":"Creeper Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.creeper_spawn_egg"},{"id":"minecraft:crimson_button","localizedName":"Crimson Button","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_button"},{"id":"minecraft:crimson_door","localizedName":"Crimson Door","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_door"},{"id":"minecraft:crimson_fence","localizedName":"Crimson Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence"},{"id":"minecraft:crimson_fence_gate","localizedName":"Crimson Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fence_gate"},{"id":"minecraft:crimson_fungus","localizedName":"Crimson Fungus","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_fungus"},{"id":"minecraft:crimson_hanging_sign","localizedName":"Crimson Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.crimson_hanging_sign"},{"id":"minecraft:crimson_hyphae","localizedName":"Crimson Hyphae","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_hyphae"},{"id":"minecraft:crimson_nylium","localizedName":"Crimson Nylium","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_nylium"},{"id":"minecraft:crimson_planks","localizedName":"Crimson Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_planks"},{"id":"minecraft:crimson_pressure_plate","localizedName":"Crimson Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_pressure_plate"},{"id":"minecraft:crimson_roots","localizedName":"Crimson Roots","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_roots"},{"id":"minecraft:crimson_sign","localizedName":"Crimson Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.crimson_sign"},{"id":"minecraft:crimson_slab","localizedName":"Crimson Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_slab"},{"id":"minecraft:crimson_stairs","localizedName":"Crimson Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stairs"},{"id":"minecraft:crimson_stem","localizedName":"Crimson Stem","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_stem"},{"id":"minecraft:crimson_trapdoor","localizedName":"Crimson Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.crimson_trapdoor"},{"id":"minecraft:crossbow","localizedName":"Crossbow","maxDamage":465,"maxStackSize":1,"unlocalizedName":"item.minecraft.crossbow"},{"id":"minecraft:crying_obsidian","localizedName":"Crying Obsidian","maxStackSize":64,"unlocalizedName":"block.minecraft.crying_obsidian"},{"id":"minecraft:cut_copper","localizedName":"Cut Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper"},{"id":"minecraft:cut_copper_slab","localizedName":"Cut Copper Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper_slab"},{"id":"minecraft:cut_copper_stairs","localizedName":"Cut Copper Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.cut_copper_stairs"},{"id":"minecraft:cut_red_sandstone","localizedName":"Cut Red Sandstone","maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone"},{"id":"minecraft:cut_red_sandstone_slab","localizedName":"Cut Red Sandstone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.cut_red_sandstone_slab"},{"id":"minecraft:cut_sandstone","localizedName":"Cut Sandstone","maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone"},{"id":"minecraft:cut_sandstone_slab","localizedName":"Cut Sandstone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.cut_sandstone_slab"},{"id":"minecraft:cyan_banner","localizedName":"Cyan Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.cyan_banner"},{"id":"minecraft:cyan_bed","localizedName":"Cyan Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_bed"},{"id":"minecraft:cyan_bundle","localizedName":"Cyan Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.cyan_bundle"},{"id":"minecraft:cyan_candle","localizedName":"Cyan Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_candle"},{"id":"minecraft:cyan_carpet","localizedName":"Cyan Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_carpet"},{"id":"minecraft:cyan_concrete","localizedName":"Cyan Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete"},{"id":"minecraft:cyan_concrete_powder","localizedName":"Cyan Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_concrete_powder"},{"id":"minecraft:cyan_dye","localizedName":"Cyan Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.cyan_dye"},{"id":"minecraft:cyan_glazed_terracotta","localizedName":"Cyan Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_glazed_terracotta"},{"id":"minecraft:cyan_shulker_box","localizedName":"Cyan Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.cyan_shulker_box"},{"id":"minecraft:cyan_stained_glass","localizedName":"Cyan Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass"},{"id":"minecraft:cyan_stained_glass_pane","localizedName":"Cyan Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_stained_glass_pane"},{"id":"minecraft:cyan_terracotta","localizedName":"Cyan Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_terracotta"},{"id":"minecraft:cyan_wool","localizedName":"Cyan Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.cyan_wool"},{"id":"minecraft:damaged_anvil","localizedName":"Damaged Anvil","maxStackSize":64,"unlocalizedName":"block.minecraft.damaged_anvil"},{"id":"minecraft:dandelion","localizedName":"Dandelion","maxStackSize":64,"unlocalizedName":"block.minecraft.dandelion"},{"id":"minecraft:danger_pottery_sherd","localizedName":"Danger Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.danger_pottery_sherd"},{"id":"minecraft:dark_oak_boat","localizedName":"Dark Oak Boat","maxStackSize":1,"unlocalizedName":"item.minecraft.dark_oak_boat"},{"id":"minecraft:dark_oak_button","localizedName":"Dark Oak Button","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_button"},{"id":"minecraft:dark_oak_chest_boat","localizedName":"Dark Oak Boat with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.dark_oak_chest_boat"},{"id":"minecraft:dark_oak_door","localizedName":"Dark Oak Door","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_door"},{"id":"minecraft:dark_oak_fence","localizedName":"Dark Oak Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence"},{"id":"minecraft:dark_oak_fence_gate","localizedName":"Dark Oak Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_fence_gate"},{"id":"minecraft:dark_oak_hanging_sign","localizedName":"Dark Oak Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.dark_oak_hanging_sign"},{"id":"minecraft:dark_oak_leaves","localizedName":"Dark Oak Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_leaves"},{"id":"minecraft:dark_oak_log","localizedName":"Dark Oak Log","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_log"},{"id":"minecraft:dark_oak_planks","localizedName":"Dark Oak Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_planks"},{"id":"minecraft:dark_oak_pressure_plate","localizedName":"Dark Oak Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_pressure_plate"},{"id":"minecraft:dark_oak_sapling","localizedName":"Dark Oak Sapling","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_sapling"},{"id":"minecraft:dark_oak_sign","localizedName":"Dark Oak Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.dark_oak_sign"},{"id":"minecraft:dark_oak_slab","localizedName":"Dark Oak Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_slab"},{"id":"minecraft:dark_oak_stairs","localizedName":"Dark Oak Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_stairs"},{"id":"minecraft:dark_oak_trapdoor","localizedName":"Dark Oak Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_trapdoor"},{"id":"minecraft:dark_oak_wood","localizedName":"Dark Oak Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_oak_wood"},{"id":"minecraft:dark_prismarine","localizedName":"Dark Prismarine","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine"},{"id":"minecraft:dark_prismarine_slab","localizedName":"Dark Prismarine Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_slab"},{"id":"minecraft:dark_prismarine_stairs","localizedName":"Dark Prismarine Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.dark_prismarine_stairs"},{"id":"minecraft:daylight_detector","localizedName":"Daylight Detector","maxStackSize":64,"unlocalizedName":"block.minecraft.daylight_detector"},{"id":"minecraft:dead_brain_coral","localizedName":"Dead Brain Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral"},{"id":"minecraft:dead_brain_coral_block","localizedName":"Dead Brain Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_block"},{"id":"minecraft:dead_brain_coral_fan","localizedName":"Dead Brain Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_brain_coral_fan"},{"id":"minecraft:dead_bubble_coral","localizedName":"Dead Bubble Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral"},{"id":"minecraft:dead_bubble_coral_block","localizedName":"Dead Bubble Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_block"},{"id":"minecraft:dead_bubble_coral_fan","localizedName":"Dead Bubble Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bubble_coral_fan"},{"id":"minecraft:dead_bush","localizedName":"Dead Bush","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_bush"},{"id":"minecraft:dead_fire_coral","localizedName":"Dead Fire Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral"},{"id":"minecraft:dead_fire_coral_block","localizedName":"Dead Fire Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_block"},{"id":"minecraft:dead_fire_coral_fan","localizedName":"Dead Fire Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_fire_coral_fan"},{"id":"minecraft:dead_horn_coral","localizedName":"Dead Horn Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral"},{"id":"minecraft:dead_horn_coral_block","localizedName":"Dead Horn Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_block"},{"id":"minecraft:dead_horn_coral_fan","localizedName":"Dead Horn Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_horn_coral_fan"},{"id":"minecraft:dead_tube_coral","localizedName":"Dead Tube Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral"},{"id":"minecraft:dead_tube_coral_block","localizedName":"Dead Tube Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_block"},{"id":"minecraft:dead_tube_coral_fan","localizedName":"Dead Tube Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.dead_tube_coral_fan"},{"id":"minecraft:debug_stick","localizedName":"Debug Stick","maxStackSize":1,"unlocalizedName":"item.minecraft.debug_stick"},{"id":"minecraft:decorated_pot","localizedName":"Decorated Pot","maxStackSize":64,"unlocalizedName":"block.minecraft.decorated_pot"},{"id":"minecraft:deepslate","localizedName":"Deepslate","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate"},{"id":"minecraft:deepslate_brick_slab","localizedName":"Deepslate Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_slab"},{"id":"minecraft:deepslate_brick_stairs","localizedName":"Deepslate Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_stairs"},{"id":"minecraft:deepslate_brick_wall","localizedName":"Deepslate Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_brick_wall"},{"id":"minecraft:deepslate_bricks","localizedName":"Deepslate Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_bricks"},{"id":"minecraft:deepslate_coal_ore","localizedName":"Deepslate Coal Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_coal_ore"},{"id":"minecraft:deepslate_copper_ore","localizedName":"Deepslate Copper Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_copper_ore"},{"id":"minecraft:deepslate_diamond_ore","localizedName":"Deepslate Diamond Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_diamond_ore"},{"id":"minecraft:deepslate_emerald_ore","localizedName":"Deepslate Emerald Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_emerald_ore"},{"id":"minecraft:deepslate_gold_ore","localizedName":"Deepslate Gold Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_gold_ore"},{"id":"minecraft:deepslate_iron_ore","localizedName":"Deepslate Iron Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_iron_ore"},{"id":"minecraft:deepslate_lapis_ore","localizedName":"Deepslate Lapis Lazuli Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_lapis_ore"},{"id":"minecraft:deepslate_redstone_ore","localizedName":"Deepslate Redstone Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_redstone_ore"},{"id":"minecraft:deepslate_tile_slab","localizedName":"Deepslate Tile Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_slab"},{"id":"minecraft:deepslate_tile_stairs","localizedName":"Deepslate Tile Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_stairs"},{"id":"minecraft:deepslate_tile_wall","localizedName":"Deepslate Tile Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tile_wall"},{"id":"minecraft:deepslate_tiles","localizedName":"Deepslate Tiles","maxStackSize":64,"unlocalizedName":"block.minecraft.deepslate_tiles"},{"id":"minecraft:detector_rail","localizedName":"Detector Rail","maxStackSize":64,"unlocalizedName":"block.minecraft.detector_rail"},{"id":"minecraft:diamond","localizedName":"Diamond","maxStackSize":64,"unlocalizedName":"item.minecraft.diamond"},{"id":"minecraft:diamond_axe","localizedName":"Diamond Axe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_axe"},{"id":"minecraft:diamond_block","localizedName":"Block of Diamond","maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_block"},{"id":"minecraft:diamond_boots","localizedName":"Diamond Boots","maxDamage":429,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_boots"},{"id":"minecraft:diamond_chestplate","localizedName":"Diamond Chestplate","maxDamage":528,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_chestplate"},{"id":"minecraft:diamond_helmet","localizedName":"Diamond Helmet","maxDamage":363,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_helmet"},{"id":"minecraft:diamond_hoe","localizedName":"Diamond Hoe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_hoe"},{"id":"minecraft:diamond_horse_armor","localizedName":"Diamond Horse Armor","maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_horse_armor"},{"id":"minecraft:diamond_leggings","localizedName":"Diamond Leggings","maxDamage":495,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_leggings"},{"id":"minecraft:diamond_ore","localizedName":"Diamond Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.diamond_ore"},{"id":"minecraft:diamond_pickaxe","localizedName":"Diamond Pickaxe","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_pickaxe"},{"id":"minecraft:diamond_shovel","localizedName":"Diamond Shovel","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_shovel"},{"id":"minecraft:diamond_sword","localizedName":"Diamond Sword","maxDamage":1561,"maxStackSize":1,"unlocalizedName":"item.minecraft.diamond_sword"},{"id":"minecraft:diorite","localizedName":"Diorite","maxStackSize":64,"unlocalizedName":"block.minecraft.diorite"},{"id":"minecraft:diorite_slab","localizedName":"Diorite Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_slab"},{"id":"minecraft:diorite_stairs","localizedName":"Diorite Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_stairs"},{"id":"minecraft:diorite_wall","localizedName":"Diorite Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.diorite_wall"},{"id":"minecraft:dirt","localizedName":"Dirt","maxStackSize":64,"unlocalizedName":"block.minecraft.dirt"},{"id":"minecraft:dirt_path","localizedName":"Dirt Path","maxStackSize":64,"unlocalizedName":"block.minecraft.dirt_path"},{"id":"minecraft:disc_fragment_5","localizedName":"Disc Fragment","maxStackSize":64,"unlocalizedName":"item.minecraft.disc_fragment_5"},{"id":"minecraft:dispenser","localizedName":"Dispenser","maxStackSize":64,"unlocalizedName":"block.minecraft.dispenser"},{"id":"minecraft:dolphin_spawn_egg","localizedName":"Dolphin Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.dolphin_spawn_egg"},{"id":"minecraft:donkey_spawn_egg","localizedName":"Donkey Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.donkey_spawn_egg"},{"id":"minecraft:dragon_breath","localizedName":"Dragon\u0027s Breath","maxStackSize":64,"unlocalizedName":"item.minecraft.dragon_breath"},{"id":"minecraft:dragon_egg","localizedName":"Dragon Egg","maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_egg"},{"id":"minecraft:dragon_head","localizedName":"Dragon Head","maxStackSize":64,"unlocalizedName":"block.minecraft.dragon_head"},{"id":"minecraft:dried_kelp","localizedName":"Dried Kelp","maxStackSize":64,"unlocalizedName":"item.minecraft.dried_kelp"},{"id":"minecraft:dried_kelp_block","localizedName":"Dried Kelp Block","maxStackSize":64,"unlocalizedName":"block.minecraft.dried_kelp_block"},{"id":"minecraft:dripstone_block","localizedName":"Dripstone Block","maxStackSize":64,"unlocalizedName":"block.minecraft.dripstone_block"},{"id":"minecraft:dropper","localizedName":"Dropper","maxStackSize":64,"unlocalizedName":"block.minecraft.dropper"},{"id":"minecraft:drowned_spawn_egg","localizedName":"Drowned Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.drowned_spawn_egg"},{"id":"minecraft:dune_armor_trim_smithing_template","localizedName":"Dune Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.dune_armor_trim_smithing_template"},{"id":"minecraft:echo_shard","localizedName":"Echo Shard","maxStackSize":64,"unlocalizedName":"item.minecraft.echo_shard"},{"id":"minecraft:egg","localizedName":"Egg","maxStackSize":16,"unlocalizedName":"item.minecraft.egg"},{"id":"minecraft:elder_guardian_spawn_egg","localizedName":"Elder Guardian Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.elder_guardian_spawn_egg"},{"id":"minecraft:elytra","localizedName":"Elytra","maxDamage":432,"maxStackSize":1,"unlocalizedName":"item.minecraft.elytra"},{"id":"minecraft:emerald","localizedName":"Emerald","maxStackSize":64,"unlocalizedName":"item.minecraft.emerald"},{"id":"minecraft:emerald_block","localizedName":"Block of Emerald","maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_block"},{"id":"minecraft:emerald_ore","localizedName":"Emerald Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.emerald_ore"},{"id":"minecraft:enchanted_book","localizedName":"Enchanted Book","maxStackSize":1,"unlocalizedName":"item.minecraft.enchanted_book"},{"id":"minecraft:enchanted_golden_apple","localizedName":"Enchanted Golden Apple","maxStackSize":64,"unlocalizedName":"item.minecraft.enchanted_golden_apple"},{"id":"minecraft:enchanting_table","localizedName":"Enchanting Table","maxStackSize":64,"unlocalizedName":"block.minecraft.enchanting_table"},{"id":"minecraft:end_crystal","localizedName":"End Crystal","maxStackSize":64,"unlocalizedName":"item.minecraft.end_crystal"},{"id":"minecraft:end_portal_frame","localizedName":"End Portal Frame","maxStackSize":64,"unlocalizedName":"block.minecraft.end_portal_frame"},{"id":"minecraft:end_rod","localizedName":"End Rod","maxStackSize":64,"unlocalizedName":"block.minecraft.end_rod"},{"id":"minecraft:end_stone","localizedName":"End Stone","maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone"},{"id":"minecraft:end_stone_brick_slab","localizedName":"End Stone Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_slab"},{"id":"minecraft:end_stone_brick_stairs","localizedName":"End Stone Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_stairs"},{"id":"minecraft:end_stone_brick_wall","localizedName":"End Stone Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_brick_wall"},{"id":"minecraft:end_stone_bricks","localizedName":"End Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.end_stone_bricks"},{"id":"minecraft:ender_chest","localizedName":"Ender Chest","maxStackSize":64,"unlocalizedName":"block.minecraft.ender_chest"},{"id":"minecraft:ender_dragon_spawn_egg","localizedName":"Ender Dragon Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.ender_dragon_spawn_egg"},{"id":"minecraft:ender_eye","localizedName":"Eye of Ender","maxStackSize":64,"unlocalizedName":"item.minecraft.ender_eye"},{"id":"minecraft:ender_pearl","localizedName":"Ender Pearl","maxStackSize":16,"unlocalizedName":"item.minecraft.ender_pearl"},{"id":"minecraft:enderman_spawn_egg","localizedName":"Enderman Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.enderman_spawn_egg"},{"id":"minecraft:endermite_spawn_egg","localizedName":"Endermite Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.endermite_spawn_egg"},{"id":"minecraft:evoker_spawn_egg","localizedName":"Evoker Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.evoker_spawn_egg"},{"id":"minecraft:experience_bottle","localizedName":"Bottle o\u0027 Enchanting","maxStackSize":64,"unlocalizedName":"item.minecraft.experience_bottle"},{"id":"minecraft:explorer_pottery_sherd","localizedName":"Explorer Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.explorer_pottery_sherd"},{"id":"minecraft:exposed_chiseled_copper","localizedName":"Exposed Chiseled Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_chiseled_copper"},{"id":"minecraft:exposed_copper","localizedName":"Exposed Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_copper"},{"id":"minecraft:exposed_copper_bulb","localizedName":"Exposed Copper Bulb","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_copper_bulb"},{"id":"minecraft:exposed_copper_door","localizedName":"Exposed Copper Door","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_copper_door"},{"id":"minecraft:exposed_copper_grate","localizedName":"Exposed Copper Grate","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_copper_grate"},{"id":"minecraft:exposed_copper_trapdoor","localizedName":"Exposed Copper Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_copper_trapdoor"},{"id":"minecraft:exposed_cut_copper","localizedName":"Exposed Cut Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper"},{"id":"minecraft:exposed_cut_copper_slab","localizedName":"Exposed Cut Copper Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper_slab"},{"id":"minecraft:exposed_cut_copper_stairs","localizedName":"Exposed Cut Copper Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.exposed_cut_copper_stairs"},{"id":"minecraft:eye_armor_trim_smithing_template","localizedName":"Eye Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.eye_armor_trim_smithing_template"},{"id":"minecraft:farmland","localizedName":"Farmland","maxStackSize":64,"unlocalizedName":"block.minecraft.farmland"},{"id":"minecraft:feather","localizedName":"Feather","maxStackSize":64,"unlocalizedName":"item.minecraft.feather"},{"id":"minecraft:fermented_spider_eye","localizedName":"Fermented Spider Eye","maxStackSize":64,"unlocalizedName":"item.minecraft.fermented_spider_eye"},{"id":"minecraft:fern","localizedName":"Fern","maxStackSize":64,"unlocalizedName":"block.minecraft.fern"},{"id":"minecraft:field_masoned_banner_pattern","localizedName":"Field Masoned Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.field_masoned_banner_pattern"},{"id":"minecraft:filled_map","localizedName":"Map","maxStackSize":64,"unlocalizedName":"item.minecraft.filled_map"},{"id":"minecraft:fire_charge","localizedName":"Fire Charge","maxStackSize":64,"unlocalizedName":"item.minecraft.fire_charge"},{"id":"minecraft:fire_coral","localizedName":"Fire Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral"},{"id":"minecraft:fire_coral_block","localizedName":"Fire Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_block"},{"id":"minecraft:fire_coral_fan","localizedName":"Fire Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.fire_coral_fan"},{"id":"minecraft:firework_rocket","localizedName":"Firework Rocket","maxStackSize":64,"unlocalizedName":"item.minecraft.firework_rocket"},{"id":"minecraft:firework_star","localizedName":"Firework Star","maxStackSize":64,"unlocalizedName":"item.minecraft.firework_star"},{"id":"minecraft:fishing_rod","localizedName":"Fishing Rod","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.fishing_rod"},{"id":"minecraft:fletching_table","localizedName":"Fletching Table","maxStackSize":64,"unlocalizedName":"block.minecraft.fletching_table"},{"id":"minecraft:flint","localizedName":"Flint","maxStackSize":64,"unlocalizedName":"item.minecraft.flint"},{"id":"minecraft:flint_and_steel","localizedName":"Flint and Steel","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.flint_and_steel"},{"id":"minecraft:flow_armor_trim_smithing_template","localizedName":"Flow Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.flow_armor_trim_smithing_template"},{"id":"minecraft:flow_banner_pattern","localizedName":"Flow Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.flow_banner_pattern"},{"id":"minecraft:flow_pottery_sherd","localizedName":"Flow Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.flow_pottery_sherd"},{"id":"minecraft:flower_banner_pattern","localizedName":"Flower Charge Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.flower_banner_pattern"},{"id":"minecraft:flower_pot","localizedName":"Flower Pot","maxStackSize":64,"unlocalizedName":"block.minecraft.flower_pot"},{"id":"minecraft:flowering_azalea","localizedName":"Flowering Azalea","maxStackSize":64,"unlocalizedName":"block.minecraft.flowering_azalea"},{"id":"minecraft:flowering_azalea_leaves","localizedName":"Flowering Azalea Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.flowering_azalea_leaves"},{"id":"minecraft:fox_spawn_egg","localizedName":"Fox Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.fox_spawn_egg"},{"id":"minecraft:friend_pottery_sherd","localizedName":"Friend Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.friend_pottery_sherd"},{"id":"minecraft:frog_spawn_egg","localizedName":"Frog Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.frog_spawn_egg"},{"id":"minecraft:frogspawn","localizedName":"Frogspawn","maxStackSize":64,"unlocalizedName":"block.minecraft.frogspawn"},{"id":"minecraft:furnace","localizedName":"Furnace","maxStackSize":64,"unlocalizedName":"block.minecraft.furnace"},{"id":"minecraft:furnace_minecart","localizedName":"Minecart with Furnace","maxStackSize":1,"unlocalizedName":"item.minecraft.furnace_minecart"},{"id":"minecraft:ghast_spawn_egg","localizedName":"Ghast Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_spawn_egg"},{"id":"minecraft:ghast_tear","localizedName":"Ghast Tear","maxStackSize":64,"unlocalizedName":"item.minecraft.ghast_tear"},{"id":"minecraft:gilded_blackstone","localizedName":"Gilded Blackstone","maxStackSize":64,"unlocalizedName":"block.minecraft.gilded_blackstone"},{"id":"minecraft:glass","localizedName":"Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.glass"},{"id":"minecraft:glass_bottle","localizedName":"Glass Bottle","maxStackSize":64,"unlocalizedName":"item.minecraft.glass_bottle"},{"id":"minecraft:glass_pane","localizedName":"Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.glass_pane"},{"id":"minecraft:glistering_melon_slice","localizedName":"Glistering Melon Slice","maxStackSize":64,"unlocalizedName":"item.minecraft.glistering_melon_slice"},{"id":"minecraft:globe_banner_pattern","localizedName":"Globe Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.globe_banner_pattern"},{"id":"minecraft:glow_berries","localizedName":"Glow Berries","maxStackSize":64,"unlocalizedName":"item.minecraft.glow_berries"},{"id":"minecraft:glow_ink_sac","localizedName":"Glow Ink Sac","maxStackSize":64,"unlocalizedName":"item.minecraft.glow_ink_sac"},{"id":"minecraft:glow_item_frame","localizedName":"Glow Item Frame","maxStackSize":64,"unlocalizedName":"item.minecraft.glow_item_frame"},{"id":"minecraft:glow_lichen","localizedName":"Glow Lichen","maxStackSize":64,"unlocalizedName":"block.minecraft.glow_lichen"},{"id":"minecraft:glow_squid_spawn_egg","localizedName":"Glow Squid Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.glow_squid_spawn_egg"},{"id":"minecraft:glowstone","localizedName":"Glowstone","maxStackSize":64,"unlocalizedName":"block.minecraft.glowstone"},{"id":"minecraft:glowstone_dust","localizedName":"Glowstone Dust","maxStackSize":64,"unlocalizedName":"item.minecraft.glowstone_dust"},{"id":"minecraft:goat_horn","localizedName":"Goat Horn","maxStackSize":1,"unlocalizedName":"item.minecraft.goat_horn"},{"id":"minecraft:goat_spawn_egg","localizedName":"Goat Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.goat_spawn_egg"},{"id":"minecraft:gold_block","localizedName":"Block of Gold","maxStackSize":64,"unlocalizedName":"block.minecraft.gold_block"},{"id":"minecraft:gold_ingot","localizedName":"Gold Ingot","maxStackSize":64,"unlocalizedName":"item.minecraft.gold_ingot"},{"id":"minecraft:gold_nugget","localizedName":"Gold Nugget","maxStackSize":64,"unlocalizedName":"item.minecraft.gold_nugget"},{"id":"minecraft:gold_ore","localizedName":"Gold Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.gold_ore"},{"id":"minecraft:golden_apple","localizedName":"Golden Apple","maxStackSize":64,"unlocalizedName":"item.minecraft.golden_apple"},{"id":"minecraft:golden_axe","localizedName":"Golden Axe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_axe"},{"id":"minecraft:golden_boots","localizedName":"Golden Boots","maxDamage":91,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_boots"},{"id":"minecraft:golden_carrot","localizedName":"Golden Carrot","maxStackSize":64,"unlocalizedName":"item.minecraft.golden_carrot"},{"id":"minecraft:golden_chestplate","localizedName":"Golden Chestplate","maxDamage":112,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_chestplate"},{"id":"minecraft:golden_helmet","localizedName":"Golden Helmet","maxDamage":77,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_helmet"},{"id":"minecraft:golden_hoe","localizedName":"Golden Hoe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_hoe"},{"id":"minecraft:golden_horse_armor","localizedName":"Golden Horse Armor","maxStackSize":1,"unlocalizedName":"item.minecraft.golden_horse_armor"},{"id":"minecraft:golden_leggings","localizedName":"Golden Leggings","maxDamage":105,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_leggings"},{"id":"minecraft:golden_pickaxe","localizedName":"Golden Pickaxe","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_pickaxe"},{"id":"minecraft:golden_shovel","localizedName":"Golden Shovel","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_shovel"},{"id":"minecraft:golden_sword","localizedName":"Golden Sword","maxDamage":32,"maxStackSize":1,"unlocalizedName":"item.minecraft.golden_sword"},{"id":"minecraft:granite","localizedName":"Granite","maxStackSize":64,"unlocalizedName":"block.minecraft.granite"},{"id":"minecraft:granite_slab","localizedName":"Granite Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.granite_slab"},{"id":"minecraft:granite_stairs","localizedName":"Granite Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.granite_stairs"},{"id":"minecraft:granite_wall","localizedName":"Granite Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.granite_wall"},{"id":"minecraft:grass_block","localizedName":"Grass Block","maxStackSize":64,"unlocalizedName":"block.minecraft.grass_block"},{"id":"minecraft:gravel","localizedName":"Gravel","maxStackSize":64,"unlocalizedName":"block.minecraft.gravel"},{"id":"minecraft:gray_banner","localizedName":"Gray Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.gray_banner"},{"id":"minecraft:gray_bed","localizedName":"Gray Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.gray_bed"},{"id":"minecraft:gray_bundle","localizedName":"Gray Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.gray_bundle"},{"id":"minecraft:gray_candle","localizedName":"Gray Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_candle"},{"id":"minecraft:gray_carpet","localizedName":"Gray Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_carpet"},{"id":"minecraft:gray_concrete","localizedName":"Gray Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete"},{"id":"minecraft:gray_concrete_powder","localizedName":"Gray Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_concrete_powder"},{"id":"minecraft:gray_dye","localizedName":"Gray Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.gray_dye"},{"id":"minecraft:gray_glazed_terracotta","localizedName":"Gray Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_glazed_terracotta"},{"id":"minecraft:gray_shulker_box","localizedName":"Gray Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.gray_shulker_box"},{"id":"minecraft:gray_stained_glass","localizedName":"Gray Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass"},{"id":"minecraft:gray_stained_glass_pane","localizedName":"Gray Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_stained_glass_pane"},{"id":"minecraft:gray_terracotta","localizedName":"Gray Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_terracotta"},{"id":"minecraft:gray_wool","localizedName":"Gray Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.gray_wool"},{"id":"minecraft:green_banner","localizedName":"Green Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.green_banner"},{"id":"minecraft:green_bed","localizedName":"Green Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.green_bed"},{"id":"minecraft:green_bundle","localizedName":"Green Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.green_bundle"},{"id":"minecraft:green_candle","localizedName":"Green Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.green_candle"},{"id":"minecraft:green_carpet","localizedName":"Green Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.green_carpet"},{"id":"minecraft:green_concrete","localizedName":"Green Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete"},{"id":"minecraft:green_concrete_powder","localizedName":"Green Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.green_concrete_powder"},{"id":"minecraft:green_dye","localizedName":"Green Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.green_dye"},{"id":"minecraft:green_glazed_terracotta","localizedName":"Green Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.green_glazed_terracotta"},{"id":"minecraft:green_shulker_box","localizedName":"Green Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.green_shulker_box"},{"id":"minecraft:green_stained_glass","localizedName":"Green Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass"},{"id":"minecraft:green_stained_glass_pane","localizedName":"Green Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.green_stained_glass_pane"},{"id":"minecraft:green_terracotta","localizedName":"Green Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.green_terracotta"},{"id":"minecraft:green_wool","localizedName":"Green Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.green_wool"},{"id":"minecraft:grindstone","localizedName":"Grindstone","maxStackSize":64,"unlocalizedName":"block.minecraft.grindstone"},{"id":"minecraft:guardian_spawn_egg","localizedName":"Guardian Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.guardian_spawn_egg"},{"id":"minecraft:gunpowder","localizedName":"Gunpowder","maxStackSize":64,"unlocalizedName":"item.minecraft.gunpowder"},{"id":"minecraft:guster_banner_pattern","localizedName":"Guster Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.guster_banner_pattern"},{"id":"minecraft:guster_pottery_sherd","localizedName":"Guster Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.guster_pottery_sherd"},{"id":"minecraft:hanging_roots","localizedName":"Hanging Roots","maxStackSize":64,"unlocalizedName":"block.minecraft.hanging_roots"},{"id":"minecraft:hay_block","localizedName":"Hay Bale","maxStackSize":64,"unlocalizedName":"block.minecraft.hay_block"},{"id":"minecraft:heart_of_the_sea","localizedName":"Heart of the Sea","maxStackSize":64,"unlocalizedName":"item.minecraft.heart_of_the_sea"},{"id":"minecraft:heart_pottery_sherd","localizedName":"Heart Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.heart_pottery_sherd"},{"id":"minecraft:heartbreak_pottery_sherd","localizedName":"Heartbreak Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.heartbreak_pottery_sherd"},{"id":"minecraft:heavy_core","localizedName":"Heavy Core","maxStackSize":64,"unlocalizedName":"block.minecraft.heavy_core"},{"id":"minecraft:heavy_weighted_pressure_plate","localizedName":"Heavy Weighted Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.heavy_weighted_pressure_plate"},{"id":"minecraft:hoglin_spawn_egg","localizedName":"Hoglin Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.hoglin_spawn_egg"},{"id":"minecraft:honey_block","localizedName":"Honey Block","maxStackSize":64,"unlocalizedName":"block.minecraft.honey_block"},{"id":"minecraft:honey_bottle","localizedName":"Honey Bottle","maxStackSize":16,"unlocalizedName":"item.minecraft.honey_bottle"},{"id":"minecraft:honeycomb","localizedName":"Honeycomb","maxStackSize":64,"unlocalizedName":"item.minecraft.honeycomb"},{"id":"minecraft:honeycomb_block","localizedName":"Honeycomb Block","maxStackSize":64,"unlocalizedName":"block.minecraft.honeycomb_block"},{"id":"minecraft:hopper","localizedName":"Hopper","maxStackSize":64,"unlocalizedName":"block.minecraft.hopper"},{"id":"minecraft:hopper_minecart","localizedName":"Minecart with Hopper","maxStackSize":1,"unlocalizedName":"item.minecraft.hopper_minecart"},{"id":"minecraft:horn_coral","localizedName":"Horn Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral"},{"id":"minecraft:horn_coral_block","localizedName":"Horn Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_block"},{"id":"minecraft:horn_coral_fan","localizedName":"Horn Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.horn_coral_fan"},{"id":"minecraft:horse_spawn_egg","localizedName":"Horse Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.horse_spawn_egg"},{"id":"minecraft:host_armor_trim_smithing_template","localizedName":"Host Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.host_armor_trim_smithing_template"},{"id":"minecraft:howl_pottery_sherd","localizedName":"Howl Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.howl_pottery_sherd"},{"id":"minecraft:husk_spawn_egg","localizedName":"Husk Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.husk_spawn_egg"},{"id":"minecraft:ice","localizedName":"Ice","maxStackSize":64,"unlocalizedName":"block.minecraft.ice"},{"id":"minecraft:infested_chiseled_stone_bricks","localizedName":"Infested Chiseled Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.infested_chiseled_stone_bricks"},{"id":"minecraft:infested_cobblestone","localizedName":"Infested Cobblestone","maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cobblestone"},{"id":"minecraft:infested_cracked_stone_bricks","localizedName":"Infested Cracked Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.infested_cracked_stone_bricks"},{"id":"minecraft:infested_deepslate","localizedName":"Infested Deepslate","maxStackSize":64,"unlocalizedName":"block.minecraft.infested_deepslate"},{"id":"minecraft:infested_mossy_stone_bricks","localizedName":"Infested Mossy Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.infested_mossy_stone_bricks"},{"id":"minecraft:infested_stone","localizedName":"Infested Stone","maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone"},{"id":"minecraft:infested_stone_bricks","localizedName":"Infested Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.infested_stone_bricks"},{"id":"minecraft:ink_sac","localizedName":"Ink Sac","maxStackSize":64,"unlocalizedName":"item.minecraft.ink_sac"},{"id":"minecraft:iron_axe","localizedName":"Iron Axe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_axe"},{"id":"minecraft:iron_bars","localizedName":"Iron Bars","maxStackSize":64,"unlocalizedName":"block.minecraft.iron_bars"},{"id":"minecraft:iron_block","localizedName":"Block of Iron","maxStackSize":64,"unlocalizedName":"block.minecraft.iron_block"},{"id":"minecraft:iron_boots","localizedName":"Iron Boots","maxDamage":195,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_boots"},{"id":"minecraft:iron_chestplate","localizedName":"Iron Chestplate","maxDamage":240,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_chestplate"},{"id":"minecraft:iron_door","localizedName":"Iron Door","maxStackSize":64,"unlocalizedName":"block.minecraft.iron_door"},{"id":"minecraft:iron_golem_spawn_egg","localizedName":"Iron Golem Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.iron_golem_spawn_egg"},{"id":"minecraft:iron_helmet","localizedName":"Iron Helmet","maxDamage":165,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_helmet"},{"id":"minecraft:iron_hoe","localizedName":"Iron Hoe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_hoe"},{"id":"minecraft:iron_horse_armor","localizedName":"Iron Horse Armor","maxStackSize":1,"unlocalizedName":"item.minecraft.iron_horse_armor"},{"id":"minecraft:iron_ingot","localizedName":"Iron Ingot","maxStackSize":64,"unlocalizedName":"item.minecraft.iron_ingot"},{"id":"minecraft:iron_leggings","localizedName":"Iron Leggings","maxDamage":225,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_leggings"},{"id":"minecraft:iron_nugget","localizedName":"Iron Nugget","maxStackSize":64,"unlocalizedName":"item.minecraft.iron_nugget"},{"id":"minecraft:iron_ore","localizedName":"Iron Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.iron_ore"},{"id":"minecraft:iron_pickaxe","localizedName":"Iron Pickaxe","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_pickaxe"},{"id":"minecraft:iron_shovel","localizedName":"Iron Shovel","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_shovel"},{"id":"minecraft:iron_sword","localizedName":"Iron Sword","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.iron_sword"},{"id":"minecraft:iron_trapdoor","localizedName":"Iron Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.iron_trapdoor"},{"id":"minecraft:item_frame","localizedName":"Item Frame","maxStackSize":64,"unlocalizedName":"item.minecraft.item_frame"},{"id":"minecraft:jack_o_lantern","localizedName":"Jack o\u0027Lantern","maxStackSize":64,"unlocalizedName":"block.minecraft.jack_o_lantern"},{"id":"minecraft:jigsaw","localizedName":"Jigsaw Block","maxStackSize":64,"unlocalizedName":"block.minecraft.jigsaw"},{"id":"minecraft:jukebox","localizedName":"Jukebox","maxStackSize":64,"unlocalizedName":"block.minecraft.jukebox"},{"id":"minecraft:jungle_boat","localizedName":"Jungle Boat","maxStackSize":1,"unlocalizedName":"item.minecraft.jungle_boat"},{"id":"minecraft:jungle_button","localizedName":"Jungle Button","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_button"},{"id":"minecraft:jungle_chest_boat","localizedName":"Jungle Boat with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.jungle_chest_boat"},{"id":"minecraft:jungle_door","localizedName":"Jungle Door","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_door"},{"id":"minecraft:jungle_fence","localizedName":"Jungle Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence"},{"id":"minecraft:jungle_fence_gate","localizedName":"Jungle Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_fence_gate"},{"id":"minecraft:jungle_hanging_sign","localizedName":"Jungle Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.jungle_hanging_sign"},{"id":"minecraft:jungle_leaves","localizedName":"Jungle Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_leaves"},{"id":"minecraft:jungle_log","localizedName":"Jungle Log","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_log"},{"id":"minecraft:jungle_planks","localizedName":"Jungle Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_planks"},{"id":"minecraft:jungle_pressure_plate","localizedName":"Jungle Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_pressure_plate"},{"id":"minecraft:jungle_sapling","localizedName":"Jungle Sapling","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_sapling"},{"id":"minecraft:jungle_sign","localizedName":"Jungle Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.jungle_sign"},{"id":"minecraft:jungle_slab","localizedName":"Jungle Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_slab"},{"id":"minecraft:jungle_stairs","localizedName":"Jungle Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_stairs"},{"id":"minecraft:jungle_trapdoor","localizedName":"Jungle Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_trapdoor"},{"id":"minecraft:jungle_wood","localizedName":"Jungle Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.jungle_wood"},{"id":"minecraft:kelp","localizedName":"Kelp","maxStackSize":64,"unlocalizedName":"block.minecraft.kelp"},{"id":"minecraft:knowledge_book","localizedName":"Knowledge Book","maxStackSize":1,"unlocalizedName":"item.minecraft.knowledge_book"},{"id":"minecraft:ladder","localizedName":"Ladder","maxStackSize":64,"unlocalizedName":"block.minecraft.ladder"},{"id":"minecraft:lantern","localizedName":"Lantern","maxStackSize":64,"unlocalizedName":"block.minecraft.lantern"},{"id":"minecraft:lapis_block","localizedName":"Block of Lapis Lazuli","maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_block"},{"id":"minecraft:lapis_lazuli","localizedName":"Lapis Lazuli","maxStackSize":64,"unlocalizedName":"item.minecraft.lapis_lazuli"},{"id":"minecraft:lapis_ore","localizedName":"Lapis Lazuli Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.lapis_ore"},{"id":"minecraft:large_amethyst_bud","localizedName":"Large Amethyst Bud","maxStackSize":64,"unlocalizedName":"block.minecraft.large_amethyst_bud"},{"id":"minecraft:large_fern","localizedName":"Large Fern","maxStackSize":64,"unlocalizedName":"block.minecraft.large_fern"},{"id":"minecraft:lava_bucket","localizedName":"Lava Bucket","maxStackSize":1,"unlocalizedName":"item.minecraft.lava_bucket"},{"id":"minecraft:lead","localizedName":"Lead","maxStackSize":64,"unlocalizedName":"item.minecraft.lead"},{"id":"minecraft:leather","localizedName":"Leather","maxStackSize":64,"unlocalizedName":"item.minecraft.leather"},{"id":"minecraft:leather_boots","localizedName":"Leather Boots","maxDamage":65,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_boots"},{"id":"minecraft:leather_chestplate","localizedName":"Leather Tunic","maxDamage":80,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_chestplate"},{"id":"minecraft:leather_helmet","localizedName":"Leather Cap","maxDamage":55,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_helmet"},{"id":"minecraft:leather_horse_armor","localizedName":"Leather Horse Armor","maxStackSize":1,"unlocalizedName":"item.minecraft.leather_horse_armor"},{"id":"minecraft:leather_leggings","localizedName":"Leather Pants","maxDamage":75,"maxStackSize":1,"unlocalizedName":"item.minecraft.leather_leggings"},{"id":"minecraft:lectern","localizedName":"Lectern","maxStackSize":64,"unlocalizedName":"block.minecraft.lectern"},{"id":"minecraft:lever","localizedName":"Lever","maxStackSize":64,"unlocalizedName":"block.minecraft.lever"},{"id":"minecraft:light","localizedName":"Light","maxStackSize":64,"unlocalizedName":"block.minecraft.light"},{"id":"minecraft:light_blue_banner","localizedName":"Light Blue Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.light_blue_banner"},{"id":"minecraft:light_blue_bed","localizedName":"Light Blue Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_bed"},{"id":"minecraft:light_blue_bundle","localizedName":"Light Blue Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.light_blue_bundle"},{"id":"minecraft:light_blue_candle","localizedName":"Light Blue Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_candle"},{"id":"minecraft:light_blue_carpet","localizedName":"Light Blue Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_carpet"},{"id":"minecraft:light_blue_concrete","localizedName":"Light Blue Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete"},{"id":"minecraft:light_blue_concrete_powder","localizedName":"Light Blue Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_concrete_powder"},{"id":"minecraft:light_blue_dye","localizedName":"Light Blue Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.light_blue_dye"},{"id":"minecraft:light_blue_glazed_terracotta","localizedName":"Light Blue Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_glazed_terracotta"},{"id":"minecraft:light_blue_shulker_box","localizedName":"Light Blue Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.light_blue_shulker_box"},{"id":"minecraft:light_blue_stained_glass","localizedName":"Light Blue Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass"},{"id":"minecraft:light_blue_stained_glass_pane","localizedName":"Light Blue Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_stained_glass_pane"},{"id":"minecraft:light_blue_terracotta","localizedName":"Light Blue Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_terracotta"},{"id":"minecraft:light_blue_wool","localizedName":"Light Blue Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.light_blue_wool"},{"id":"minecraft:light_gray_banner","localizedName":"Light Gray Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.light_gray_banner"},{"id":"minecraft:light_gray_bed","localizedName":"Light Gray Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_bed"},{"id":"minecraft:light_gray_bundle","localizedName":"Light Gray Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.light_gray_bundle"},{"id":"minecraft:light_gray_candle","localizedName":"Light Gray Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_candle"},{"id":"minecraft:light_gray_carpet","localizedName":"Light Gray Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_carpet"},{"id":"minecraft:light_gray_concrete","localizedName":"Light Gray Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete"},{"id":"minecraft:light_gray_concrete_powder","localizedName":"Light Gray Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_concrete_powder"},{"id":"minecraft:light_gray_dye","localizedName":"Light Gray Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.light_gray_dye"},{"id":"minecraft:light_gray_glazed_terracotta","localizedName":"Light Gray Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_glazed_terracotta"},{"id":"minecraft:light_gray_shulker_box","localizedName":"Light Gray Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.light_gray_shulker_box"},{"id":"minecraft:light_gray_stained_glass","localizedName":"Light Gray Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass"},{"id":"minecraft:light_gray_stained_glass_pane","localizedName":"Light Gray Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_stained_glass_pane"},{"id":"minecraft:light_gray_terracotta","localizedName":"Light Gray Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_terracotta"},{"id":"minecraft:light_gray_wool","localizedName":"Light Gray Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.light_gray_wool"},{"id":"minecraft:light_weighted_pressure_plate","localizedName":"Light Weighted Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.light_weighted_pressure_plate"},{"id":"minecraft:lightning_rod","localizedName":"Lightning Rod","maxStackSize":64,"unlocalizedName":"block.minecraft.lightning_rod"},{"id":"minecraft:lilac","localizedName":"Lilac","maxStackSize":64,"unlocalizedName":"block.minecraft.lilac"},{"id":"minecraft:lily_of_the_valley","localizedName":"Lily of the Valley","maxStackSize":64,"unlocalizedName":"block.minecraft.lily_of_the_valley"},{"id":"minecraft:lily_pad","localizedName":"Lily Pad","maxStackSize":64,"unlocalizedName":"block.minecraft.lily_pad"},{"id":"minecraft:lime_banner","localizedName":"Lime Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.lime_banner"},{"id":"minecraft:lime_bed","localizedName":"Lime Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.lime_bed"},{"id":"minecraft:lime_bundle","localizedName":"Lime Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.lime_bundle"},{"id":"minecraft:lime_candle","localizedName":"Lime Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_candle"},{"id":"minecraft:lime_carpet","localizedName":"Lime Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_carpet"},{"id":"minecraft:lime_concrete","localizedName":"Lime Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete"},{"id":"minecraft:lime_concrete_powder","localizedName":"Lime Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_concrete_powder"},{"id":"minecraft:lime_dye","localizedName":"Lime Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.lime_dye"},{"id":"minecraft:lime_glazed_terracotta","localizedName":"Lime Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_glazed_terracotta"},{"id":"minecraft:lime_shulker_box","localizedName":"Lime Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.lime_shulker_box"},{"id":"minecraft:lime_stained_glass","localizedName":"Lime Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass"},{"id":"minecraft:lime_stained_glass_pane","localizedName":"Lime Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_stained_glass_pane"},{"id":"minecraft:lime_terracotta","localizedName":"Lime Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_terracotta"},{"id":"minecraft:lime_wool","localizedName":"Lime Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.lime_wool"},{"id":"minecraft:lingering_potion","localizedName":"Lingering Water Bottle","maxStackSize":1,"unlocalizedName":"item.minecraft.lingering_potion"},{"id":"minecraft:llama_spawn_egg","localizedName":"Llama Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.llama_spawn_egg"},{"id":"minecraft:lodestone","localizedName":"Lodestone","maxStackSize":64,"unlocalizedName":"block.minecraft.lodestone"},{"id":"minecraft:loom","localizedName":"Loom","maxStackSize":64,"unlocalizedName":"block.minecraft.loom"},{"id":"minecraft:mace","localizedName":"Mace","maxDamage":500,"maxStackSize":1,"unlocalizedName":"item.minecraft.mace"},{"id":"minecraft:magenta_banner","localizedName":"Magenta Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.magenta_banner"},{"id":"minecraft:magenta_bed","localizedName":"Magenta Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_bed"},{"id":"minecraft:magenta_bundle","localizedName":"Magenta Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.magenta_bundle"},{"id":"minecraft:magenta_candle","localizedName":"Magenta Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_candle"},{"id":"minecraft:magenta_carpet","localizedName":"Magenta Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_carpet"},{"id":"minecraft:magenta_concrete","localizedName":"Magenta Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete"},{"id":"minecraft:magenta_concrete_powder","localizedName":"Magenta Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_concrete_powder"},{"id":"minecraft:magenta_dye","localizedName":"Magenta Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.magenta_dye"},{"id":"minecraft:magenta_glazed_terracotta","localizedName":"Magenta Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_glazed_terracotta"},{"id":"minecraft:magenta_shulker_box","localizedName":"Magenta Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.magenta_shulker_box"},{"id":"minecraft:magenta_stained_glass","localizedName":"Magenta Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass"},{"id":"minecraft:magenta_stained_glass_pane","localizedName":"Magenta Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_stained_glass_pane"},{"id":"minecraft:magenta_terracotta","localizedName":"Magenta Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_terracotta"},{"id":"minecraft:magenta_wool","localizedName":"Magenta Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.magenta_wool"},{"id":"minecraft:magma_block","localizedName":"Magma Block","maxStackSize":64,"unlocalizedName":"block.minecraft.magma_block"},{"id":"minecraft:magma_cream","localizedName":"Magma Cream","maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cream"},{"id":"minecraft:magma_cube_spawn_egg","localizedName":"Magma Cube Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.magma_cube_spawn_egg"},{"id":"minecraft:mangrove_boat","localizedName":"Mangrove Boat","maxStackSize":1,"unlocalizedName":"item.minecraft.mangrove_boat"},{"id":"minecraft:mangrove_button","localizedName":"Mangrove Button","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_button"},{"id":"minecraft:mangrove_chest_boat","localizedName":"Mangrove Boat with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.mangrove_chest_boat"},{"id":"minecraft:mangrove_door","localizedName":"Mangrove Door","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_door"},{"id":"minecraft:mangrove_fence","localizedName":"Mangrove Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_fence"},{"id":"minecraft:mangrove_fence_gate","localizedName":"Mangrove Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_fence_gate"},{"id":"minecraft:mangrove_hanging_sign","localizedName":"Mangrove Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.mangrove_hanging_sign"},{"id":"minecraft:mangrove_leaves","localizedName":"Mangrove Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_leaves"},{"id":"minecraft:mangrove_log","localizedName":"Mangrove Log","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_log"},{"id":"minecraft:mangrove_planks","localizedName":"Mangrove Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_planks"},{"id":"minecraft:mangrove_pressure_plate","localizedName":"Mangrove Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_pressure_plate"},{"id":"minecraft:mangrove_propagule","localizedName":"Mangrove Propagule","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_propagule"},{"id":"minecraft:mangrove_roots","localizedName":"Mangrove Roots","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_roots"},{"id":"minecraft:mangrove_sign","localizedName":"Mangrove Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.mangrove_sign"},{"id":"minecraft:mangrove_slab","localizedName":"Mangrove Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_slab"},{"id":"minecraft:mangrove_stairs","localizedName":"Mangrove Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_stairs"},{"id":"minecraft:mangrove_trapdoor","localizedName":"Mangrove Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_trapdoor"},{"id":"minecraft:mangrove_wood","localizedName":"Mangrove Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.mangrove_wood"},{"id":"minecraft:map","localizedName":"Empty Map","maxStackSize":64,"unlocalizedName":"item.minecraft.map"},{"id":"minecraft:medium_amethyst_bud","localizedName":"Medium Amethyst Bud","maxStackSize":64,"unlocalizedName":"block.minecraft.medium_amethyst_bud"},{"id":"minecraft:melon","localizedName":"Melon","maxStackSize":64,"unlocalizedName":"block.minecraft.melon"},{"id":"minecraft:melon_seeds","localizedName":"Melon Seeds","maxStackSize":64,"unlocalizedName":"item.minecraft.melon_seeds"},{"id":"minecraft:melon_slice","localizedName":"Melon Slice","maxStackSize":64,"unlocalizedName":"item.minecraft.melon_slice"},{"id":"minecraft:milk_bucket","localizedName":"Milk Bucket","maxStackSize":1,"unlocalizedName":"item.minecraft.milk_bucket"},{"id":"minecraft:minecart","localizedName":"Minecart","maxStackSize":1,"unlocalizedName":"item.minecraft.minecart"},{"id":"minecraft:miner_pottery_sherd","localizedName":"Miner Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.miner_pottery_sherd"},{"id":"minecraft:mojang_banner_pattern","localizedName":"Thing Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.mojang_banner_pattern"},{"id":"minecraft:mooshroom_spawn_egg","localizedName":"Mooshroom Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.mooshroom_spawn_egg"},{"id":"minecraft:moss_block","localizedName":"Moss Block","maxStackSize":64,"unlocalizedName":"block.minecraft.moss_block"},{"id":"minecraft:moss_carpet","localizedName":"Moss Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.moss_carpet"},{"id":"minecraft:mossy_cobblestone","localizedName":"Mossy Cobblestone","maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone"},{"id":"minecraft:mossy_cobblestone_slab","localizedName":"Mossy Cobblestone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_slab"},{"id":"minecraft:mossy_cobblestone_stairs","localizedName":"Mossy Cobblestone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_stairs"},{"id":"minecraft:mossy_cobblestone_wall","localizedName":"Mossy Cobblestone Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_cobblestone_wall"},{"id":"minecraft:mossy_stone_brick_slab","localizedName":"Mossy Stone Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_slab"},{"id":"minecraft:mossy_stone_brick_stairs","localizedName":"Mossy Stone Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_stairs"},{"id":"minecraft:mossy_stone_brick_wall","localizedName":"Mossy Stone Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_brick_wall"},{"id":"minecraft:mossy_stone_bricks","localizedName":"Mossy Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.mossy_stone_bricks"},{"id":"minecraft:mourner_pottery_sherd","localizedName":"Mourner Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.mourner_pottery_sherd"},{"id":"minecraft:mud","localizedName":"Mud","maxStackSize":64,"unlocalizedName":"block.minecraft.mud"},{"id":"minecraft:mud_brick_slab","localizedName":"Mud Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.mud_brick_slab"},{"id":"minecraft:mud_brick_stairs","localizedName":"Mud Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.mud_brick_stairs"},{"id":"minecraft:mud_brick_wall","localizedName":"Mud Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.mud_brick_wall"},{"id":"minecraft:mud_bricks","localizedName":"Mud Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.mud_bricks"},{"id":"minecraft:muddy_mangrove_roots","localizedName":"Muddy Mangrove Roots","maxStackSize":64,"unlocalizedName":"block.minecraft.muddy_mangrove_roots"},{"id":"minecraft:mule_spawn_egg","localizedName":"Mule Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.mule_spawn_egg"},{"id":"minecraft:mushroom_stem","localizedName":"Mushroom Stem","maxStackSize":64,"unlocalizedName":"block.minecraft.mushroom_stem"},{"id":"minecraft:mushroom_stew","localizedName":"Mushroom Stew","maxStackSize":1,"unlocalizedName":"item.minecraft.mushroom_stew"},{"id":"minecraft:music_disc_11","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_11"},{"id":"minecraft:music_disc_13","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_13"},{"id":"minecraft:music_disc_5","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_5"},{"id":"minecraft:music_disc_blocks","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_blocks"},{"id":"minecraft:music_disc_cat","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_cat"},{"id":"minecraft:music_disc_chirp","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_chirp"},{"id":"minecraft:music_disc_creator","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_creator"},{"id":"minecraft:music_disc_creator_music_box","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_creator_music_box"},{"id":"minecraft:music_disc_far","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_far"},{"id":"minecraft:music_disc_mall","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mall"},{"id":"minecraft:music_disc_mellohi","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_mellohi"},{"id":"minecraft:music_disc_otherside","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_otherside"},{"id":"minecraft:music_disc_pigstep","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_pigstep"},{"id":"minecraft:music_disc_precipice","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_precipice"},{"id":"minecraft:music_disc_relic","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_relic"},{"id":"minecraft:music_disc_stal","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_stal"},{"id":"minecraft:music_disc_strad","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_strad"},{"id":"minecraft:music_disc_wait","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_wait"},{"id":"minecraft:music_disc_ward","localizedName":"Music Disc","maxStackSize":1,"unlocalizedName":"item.minecraft.music_disc_ward"},{"id":"minecraft:mutton","localizedName":"Raw Mutton","maxStackSize":64,"unlocalizedName":"item.minecraft.mutton"},{"id":"minecraft:mycelium","localizedName":"Mycelium","maxStackSize":64,"unlocalizedName":"block.minecraft.mycelium"},{"id":"minecraft:name_tag","localizedName":"Name Tag","maxStackSize":64,"unlocalizedName":"item.minecraft.name_tag"},{"id":"minecraft:nautilus_shell","localizedName":"Nautilus Shell","maxStackSize":64,"unlocalizedName":"item.minecraft.nautilus_shell"},{"id":"minecraft:nether_brick","localizedName":"Nether Brick","maxStackSize":64,"unlocalizedName":"item.minecraft.nether_brick"},{"id":"minecraft:nether_brick_fence","localizedName":"Nether Brick Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_fence"},{"id":"minecraft:nether_brick_slab","localizedName":"Nether Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_slab"},{"id":"minecraft:nether_brick_stairs","localizedName":"Nether Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_stairs"},{"id":"minecraft:nether_brick_wall","localizedName":"Nether Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_brick_wall"},{"id":"minecraft:nether_bricks","localizedName":"Nether Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_bricks"},{"id":"minecraft:nether_gold_ore","localizedName":"Nether Gold Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_gold_ore"},{"id":"minecraft:nether_quartz_ore","localizedName":"Nether Quartz Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_quartz_ore"},{"id":"minecraft:nether_sprouts","localizedName":"Nether Sprouts","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_sprouts"},{"id":"minecraft:nether_star","localizedName":"Nether Star","maxStackSize":64,"unlocalizedName":"item.minecraft.nether_star"},{"id":"minecraft:nether_wart","localizedName":"Nether Wart","maxStackSize":64,"unlocalizedName":"item.minecraft.nether_wart"},{"id":"minecraft:nether_wart_block","localizedName":"Nether Wart Block","maxStackSize":64,"unlocalizedName":"block.minecraft.nether_wart_block"},{"id":"minecraft:netherite_axe","localizedName":"Netherite Axe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_axe"},{"id":"minecraft:netherite_block","localizedName":"Block of Netherite","maxStackSize":64,"unlocalizedName":"block.minecraft.netherite_block"},{"id":"minecraft:netherite_boots","localizedName":"Netherite Boots","maxDamage":481,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_boots"},{"id":"minecraft:netherite_chestplate","localizedName":"Netherite Chestplate","maxDamage":592,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_chestplate"},{"id":"minecraft:netherite_helmet","localizedName":"Netherite Helmet","maxDamage":407,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_helmet"},{"id":"minecraft:netherite_hoe","localizedName":"Netherite Hoe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_hoe"},{"id":"minecraft:netherite_ingot","localizedName":"Netherite Ingot","maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_ingot"},{"id":"minecraft:netherite_leggings","localizedName":"Netherite Leggings","maxDamage":555,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_leggings"},{"id":"minecraft:netherite_pickaxe","localizedName":"Netherite Pickaxe","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_pickaxe"},{"id":"minecraft:netherite_scrap","localizedName":"Netherite Scrap","maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_scrap"},{"id":"minecraft:netherite_shovel","localizedName":"Netherite Shovel","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_shovel"},{"id":"minecraft:netherite_sword","localizedName":"Netherite Sword","maxDamage":2031,"maxStackSize":1,"unlocalizedName":"item.minecraft.netherite_sword"},{"id":"minecraft:netherite_upgrade_smithing_template","localizedName":"Netherite Upgrade","maxStackSize":64,"unlocalizedName":"item.minecraft.netherite_upgrade_smithing_template"},{"id":"minecraft:netherrack","localizedName":"Netherrack","maxStackSize":64,"unlocalizedName":"block.minecraft.netherrack"},{"id":"minecraft:note_block","localizedName":"Note Block","maxStackSize":64,"unlocalizedName":"block.minecraft.note_block"},{"id":"minecraft:oak_boat","localizedName":"Oak Boat","maxStackSize":1,"unlocalizedName":"item.minecraft.oak_boat"},{"id":"minecraft:oak_button","localizedName":"Oak Button","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_button"},{"id":"minecraft:oak_chest_boat","localizedName":"Oak Boat with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.oak_chest_boat"},{"id":"minecraft:oak_door","localizedName":"Oak Door","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_door"},{"id":"minecraft:oak_fence","localizedName":"Oak Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence"},{"id":"minecraft:oak_fence_gate","localizedName":"Oak Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_fence_gate"},{"id":"minecraft:oak_hanging_sign","localizedName":"Oak Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.oak_hanging_sign"},{"id":"minecraft:oak_leaves","localizedName":"Oak Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_leaves"},{"id":"minecraft:oak_log","localizedName":"Oak Log","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_log"},{"id":"minecraft:oak_planks","localizedName":"Oak Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_planks"},{"id":"minecraft:oak_pressure_plate","localizedName":"Oak Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_pressure_plate"},{"id":"minecraft:oak_sapling","localizedName":"Oak Sapling","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_sapling"},{"id":"minecraft:oak_sign","localizedName":"Oak Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.oak_sign"},{"id":"minecraft:oak_slab","localizedName":"Oak Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_slab"},{"id":"minecraft:oak_stairs","localizedName":"Oak Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_stairs"},{"id":"minecraft:oak_trapdoor","localizedName":"Oak Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_trapdoor"},{"id":"minecraft:oak_wood","localizedName":"Oak Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.oak_wood"},{"id":"minecraft:observer","localizedName":"Observer","maxStackSize":64,"unlocalizedName":"block.minecraft.observer"},{"id":"minecraft:obsidian","localizedName":"Obsidian","maxStackSize":64,"unlocalizedName":"block.minecraft.obsidian"},{"id":"minecraft:ocelot_spawn_egg","localizedName":"Ocelot Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.ocelot_spawn_egg"},{"id":"minecraft:ochre_froglight","localizedName":"Ochre Froglight","maxStackSize":64,"unlocalizedName":"block.minecraft.ochre_froglight"},{"id":"minecraft:ominous_bottle","localizedName":"Ominous Bottle","maxStackSize":64,"unlocalizedName":"item.minecraft.ominous_bottle"},{"id":"minecraft:ominous_trial_key","localizedName":"Ominous Trial Key","maxStackSize":64,"unlocalizedName":"item.minecraft.ominous_trial_key"},{"id":"minecraft:orange_banner","localizedName":"Orange Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.orange_banner"},{"id":"minecraft:orange_bed","localizedName":"Orange Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.orange_bed"},{"id":"minecraft:orange_bundle","localizedName":"Orange Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.orange_bundle"},{"id":"minecraft:orange_candle","localizedName":"Orange Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_candle"},{"id":"minecraft:orange_carpet","localizedName":"Orange Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_carpet"},{"id":"minecraft:orange_concrete","localizedName":"Orange Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete"},{"id":"minecraft:orange_concrete_powder","localizedName":"Orange Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_concrete_powder"},{"id":"minecraft:orange_dye","localizedName":"Orange Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.orange_dye"},{"id":"minecraft:orange_glazed_terracotta","localizedName":"Orange Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_glazed_terracotta"},{"id":"minecraft:orange_shulker_box","localizedName":"Orange Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.orange_shulker_box"},{"id":"minecraft:orange_stained_glass","localizedName":"Orange Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass"},{"id":"minecraft:orange_stained_glass_pane","localizedName":"Orange Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_stained_glass_pane"},{"id":"minecraft:orange_terracotta","localizedName":"Orange Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_terracotta"},{"id":"minecraft:orange_tulip","localizedName":"Orange Tulip","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_tulip"},{"id":"minecraft:orange_wool","localizedName":"Orange Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.orange_wool"},{"id":"minecraft:oxeye_daisy","localizedName":"Oxeye Daisy","maxStackSize":64,"unlocalizedName":"block.minecraft.oxeye_daisy"},{"id":"minecraft:oxidized_chiseled_copper","localizedName":"Oxidized Chiseled Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_chiseled_copper"},{"id":"minecraft:oxidized_copper","localizedName":"Oxidized Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_copper"},{"id":"minecraft:oxidized_copper_bulb","localizedName":"Oxidized Copper Bulb","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_copper_bulb"},{"id":"minecraft:oxidized_copper_door","localizedName":"Oxidized Copper Door","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_copper_door"},{"id":"minecraft:oxidized_copper_grate","localizedName":"Oxidized Copper Grate","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_copper_grate"},{"id":"minecraft:oxidized_copper_trapdoor","localizedName":"Oxidized Copper Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_copper_trapdoor"},{"id":"minecraft:oxidized_cut_copper","localizedName":"Oxidized Cut Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper"},{"id":"minecraft:oxidized_cut_copper_slab","localizedName":"Oxidized Cut Copper Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper_slab"},{"id":"minecraft:oxidized_cut_copper_stairs","localizedName":"Oxidized Cut Copper Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.oxidized_cut_copper_stairs"},{"id":"minecraft:packed_ice","localizedName":"Packed Ice","maxStackSize":64,"unlocalizedName":"block.minecraft.packed_ice"},{"id":"minecraft:packed_mud","localizedName":"Packed Mud","maxStackSize":64,"unlocalizedName":"block.minecraft.packed_mud"},{"id":"minecraft:painting","localizedName":"Painting","maxStackSize":64,"unlocalizedName":"item.minecraft.painting"},{"id":"minecraft:pale_hanging_moss","localizedName":"Pale Hanging Moss","maxStackSize":64,"unlocalizedName":"block.minecraft.pale_hanging_moss"},{"id":"minecraft:pale_moss_block","localizedName":"Pale Moss Block","maxStackSize":64,"unlocalizedName":"block.minecraft.pale_moss_block"},{"id":"minecraft:pale_moss_carpet","localizedName":"Pale Moss Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.pale_moss_carpet"},{"id":"minecraft:pale_oak_boat","localizedName":"Pale Oak Boat","maxStackSize":1,"unlocalizedName":"item.minecraft.pale_oak_boat"},{"id":"minecraft:pale_oak_button","localizedName":"Pale Oak Button","maxStackSize":64,"unlocalizedName":"block.minecraft.pale_oak_button"},{"id":"minecraft:pale_oak_chest_boat","localizedName":"Pale Oak Boat with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.pale_oak_chest_boat"},{"id":"minecraft:pale_oak_door","localizedName":"Pale Oak Door","maxStackSize":64,"unlocalizedName":"block.minecraft.pale_oak_door"},{"id":"minecraft:pale_oak_fence","localizedName":"Pale Oak Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.pale_oak_fence"},{"id":"minecraft:pale_oak_fence_gate","localizedName":"Pale Oak Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.pale_oak_fence_gate"},{"id":"minecraft:pale_oak_hanging_sign","localizedName":"Pale Oak Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.pale_oak_hanging_sign"},{"id":"minecraft:pale_oak_leaves","localizedName":"Pale Oak Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.pale_oak_leaves"},{"id":"minecraft:pale_oak_log","localizedName":"Pale Oak Log","maxStackSize":64,"unlocalizedName":"block.minecraft.pale_oak_log"},{"id":"minecraft:pale_oak_planks","localizedName":"Pale Oak Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.pale_oak_planks"},{"id":"minecraft:pale_oak_pressure_plate","localizedName":"Pale Oak Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.pale_oak_pressure_plate"},{"id":"minecraft:pale_oak_sapling","localizedName":"Pale Oak Sapling","maxStackSize":64,"unlocalizedName":"block.minecraft.pale_oak_sapling"},{"id":"minecraft:pale_oak_sign","localizedName":"Pale Oak Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.pale_oak_sign"},{"id":"minecraft:pale_oak_slab","localizedName":"Pale Oak Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.pale_oak_slab"},{"id":"minecraft:pale_oak_stairs","localizedName":"Pale Oak Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.pale_oak_stairs"},{"id":"minecraft:pale_oak_trapdoor","localizedName":"Pale Oak Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.pale_oak_trapdoor"},{"id":"minecraft:pale_oak_wood","localizedName":"Pale Oak Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.pale_oak_wood"},{"id":"minecraft:panda_spawn_egg","localizedName":"Panda Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.panda_spawn_egg"},{"id":"minecraft:paper","localizedName":"Paper","maxStackSize":64,"unlocalizedName":"item.minecraft.paper"},{"id":"minecraft:parrot_spawn_egg","localizedName":"Parrot Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.parrot_spawn_egg"},{"id":"minecraft:pearlescent_froglight","localizedName":"Pearlescent Froglight","maxStackSize":64,"unlocalizedName":"block.minecraft.pearlescent_froglight"},{"id":"minecraft:peony","localizedName":"Peony","maxStackSize":64,"unlocalizedName":"block.minecraft.peony"},{"id":"minecraft:petrified_oak_slab","localizedName":"Petrified Oak Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.petrified_oak_slab"},{"id":"minecraft:phantom_membrane","localizedName":"Phantom Membrane","maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_membrane"},{"id":"minecraft:phantom_spawn_egg","localizedName":"Phantom Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.phantom_spawn_egg"},{"id":"minecraft:pig_spawn_egg","localizedName":"Pig Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.pig_spawn_egg"},{"id":"minecraft:piglin_banner_pattern","localizedName":"Snout Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.piglin_banner_pattern"},{"id":"minecraft:piglin_brute_spawn_egg","localizedName":"Piglin Brute Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_brute_spawn_egg"},{"id":"minecraft:piglin_head","localizedName":"Piglin Head","maxStackSize":64,"unlocalizedName":"block.minecraft.piglin_head"},{"id":"minecraft:piglin_spawn_egg","localizedName":"Piglin Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.piglin_spawn_egg"},{"id":"minecraft:pillager_spawn_egg","localizedName":"Pillager Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.pillager_spawn_egg"},{"id":"minecraft:pink_banner","localizedName":"Pink Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.pink_banner"},{"id":"minecraft:pink_bed","localizedName":"Pink Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.pink_bed"},{"id":"minecraft:pink_bundle","localizedName":"Pink Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.pink_bundle"},{"id":"minecraft:pink_candle","localizedName":"Pink Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_candle"},{"id":"minecraft:pink_carpet","localizedName":"Pink Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_carpet"},{"id":"minecraft:pink_concrete","localizedName":"Pink Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete"},{"id":"minecraft:pink_concrete_powder","localizedName":"Pink Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_concrete_powder"},{"id":"minecraft:pink_dye","localizedName":"Pink Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.pink_dye"},{"id":"minecraft:pink_glazed_terracotta","localizedName":"Pink Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_glazed_terracotta"},{"id":"minecraft:pink_petals","localizedName":"Pink Petals","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_petals"},{"id":"minecraft:pink_shulker_box","localizedName":"Pink Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.pink_shulker_box"},{"id":"minecraft:pink_stained_glass","localizedName":"Pink Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass"},{"id":"minecraft:pink_stained_glass_pane","localizedName":"Pink Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_stained_glass_pane"},{"id":"minecraft:pink_terracotta","localizedName":"Pink Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_terracotta"},{"id":"minecraft:pink_tulip","localizedName":"Pink Tulip","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_tulip"},{"id":"minecraft:pink_wool","localizedName":"Pink Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.pink_wool"},{"id":"minecraft:piston","localizedName":"Piston","maxStackSize":64,"unlocalizedName":"block.minecraft.piston"},{"id":"minecraft:pitcher_plant","localizedName":"Pitcher Plant","maxStackSize":64,"unlocalizedName":"block.minecraft.pitcher_plant"},{"id":"minecraft:pitcher_pod","localizedName":"Pitcher Pod","maxStackSize":64,"unlocalizedName":"item.minecraft.pitcher_pod"},{"id":"minecraft:player_head","localizedName":"Player Head","maxStackSize":64,"unlocalizedName":"block.minecraft.player_head"},{"id":"minecraft:plenty_pottery_sherd","localizedName":"Plenty Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.plenty_pottery_sherd"},{"id":"minecraft:podzol","localizedName":"Podzol","maxStackSize":64,"unlocalizedName":"block.minecraft.podzol"},{"id":"minecraft:pointed_dripstone","localizedName":"Pointed Dripstone","maxStackSize":64,"unlocalizedName":"block.minecraft.pointed_dripstone"},{"id":"minecraft:poisonous_potato","localizedName":"Poisonous Potato","maxStackSize":64,"unlocalizedName":"item.minecraft.poisonous_potato"},{"id":"minecraft:polar_bear_spawn_egg","localizedName":"Polar Bear Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.polar_bear_spawn_egg"},{"id":"minecraft:polished_andesite","localizedName":"Polished Andesite","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite"},{"id":"minecraft:polished_andesite_slab","localizedName":"Polished Andesite Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_slab"},{"id":"minecraft:polished_andesite_stairs","localizedName":"Polished Andesite Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_andesite_stairs"},{"id":"minecraft:polished_basalt","localizedName":"Polished Basalt","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_basalt"},{"id":"minecraft:polished_blackstone","localizedName":"Polished Blackstone","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone"},{"id":"minecraft:polished_blackstone_brick_slab","localizedName":"Polished Blackstone Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_slab"},{"id":"minecraft:polished_blackstone_brick_stairs","localizedName":"Polished Blackstone Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_stairs"},{"id":"minecraft:polished_blackstone_brick_wall","localizedName":"Polished Blackstone Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_brick_wall"},{"id":"minecraft:polished_blackstone_bricks","localizedName":"Polished Blackstone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_bricks"},{"id":"minecraft:polished_blackstone_button","localizedName":"Polished Blackstone Button","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_button"},{"id":"minecraft:polished_blackstone_pressure_plate","localizedName":"Polished Blackstone Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_pressure_plate"},{"id":"minecraft:polished_blackstone_slab","localizedName":"Polished Blackstone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_slab"},{"id":"minecraft:polished_blackstone_stairs","localizedName":"Polished Blackstone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_stairs"},{"id":"minecraft:polished_blackstone_wall","localizedName":"Polished Blackstone Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_blackstone_wall"},{"id":"minecraft:polished_deepslate","localizedName":"Polished Deepslate","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate"},{"id":"minecraft:polished_deepslate_slab","localizedName":"Polished Deepslate Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_slab"},{"id":"minecraft:polished_deepslate_stairs","localizedName":"Polished Deepslate Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_stairs"},{"id":"minecraft:polished_deepslate_wall","localizedName":"Polished Deepslate Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_deepslate_wall"},{"id":"minecraft:polished_diorite","localizedName":"Polished Diorite","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite"},{"id":"minecraft:polished_diorite_slab","localizedName":"Polished Diorite Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_slab"},{"id":"minecraft:polished_diorite_stairs","localizedName":"Polished Diorite Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_diorite_stairs"},{"id":"minecraft:polished_granite","localizedName":"Polished Granite","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite"},{"id":"minecraft:polished_granite_slab","localizedName":"Polished Granite Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_slab"},{"id":"minecraft:polished_granite_stairs","localizedName":"Polished Granite Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_granite_stairs"},{"id":"minecraft:polished_tuff","localizedName":"Polished Tuff","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_tuff"},{"id":"minecraft:polished_tuff_slab","localizedName":"Polished Tuff Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_tuff_slab"},{"id":"minecraft:polished_tuff_stairs","localizedName":"Polished Tuff Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_tuff_stairs"},{"id":"minecraft:polished_tuff_wall","localizedName":"Polished Tuff Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.polished_tuff_wall"},{"id":"minecraft:popped_chorus_fruit","localizedName":"Popped Chorus Fruit","maxStackSize":64,"unlocalizedName":"item.minecraft.popped_chorus_fruit"},{"id":"minecraft:poppy","localizedName":"Poppy","maxStackSize":64,"unlocalizedName":"block.minecraft.poppy"},{"id":"minecraft:porkchop","localizedName":"Raw Porkchop","maxStackSize":64,"unlocalizedName":"item.minecraft.porkchop"},{"id":"minecraft:potato","localizedName":"Potato","maxStackSize":64,"unlocalizedName":"item.minecraft.potato"},{"id":"minecraft:potion","localizedName":"Water Bottle","maxStackSize":1,"unlocalizedName":"item.minecraft.potion"},{"id":"minecraft:powder_snow_bucket","localizedName":"Powder Snow Bucket","maxStackSize":1,"unlocalizedName":"item.minecraft.powder_snow_bucket"},{"id":"minecraft:powered_rail","localizedName":"Powered Rail","maxStackSize":64,"unlocalizedName":"block.minecraft.powered_rail"},{"id":"minecraft:prismarine","localizedName":"Prismarine","maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine"},{"id":"minecraft:prismarine_brick_slab","localizedName":"Prismarine Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_slab"},{"id":"minecraft:prismarine_brick_stairs","localizedName":"Prismarine Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_brick_stairs"},{"id":"minecraft:prismarine_bricks","localizedName":"Prismarine Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_bricks"},{"id":"minecraft:prismarine_crystals","localizedName":"Prismarine Crystals","maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_crystals"},{"id":"minecraft:prismarine_shard","localizedName":"Prismarine Shard","maxStackSize":64,"unlocalizedName":"item.minecraft.prismarine_shard"},{"id":"minecraft:prismarine_slab","localizedName":"Prismarine Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_slab"},{"id":"minecraft:prismarine_stairs","localizedName":"Prismarine Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_stairs"},{"id":"minecraft:prismarine_wall","localizedName":"Prismarine Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.prismarine_wall"},{"id":"minecraft:prize_pottery_sherd","localizedName":"Prize Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.prize_pottery_sherd"},{"id":"minecraft:pufferfish","localizedName":"Pufferfish","maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish"},{"id":"minecraft:pufferfish_bucket","localizedName":"Bucket of Pufferfish","maxStackSize":1,"unlocalizedName":"item.minecraft.pufferfish_bucket"},{"id":"minecraft:pufferfish_spawn_egg","localizedName":"Pufferfish Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.pufferfish_spawn_egg"},{"id":"minecraft:pumpkin","localizedName":"Pumpkin","maxStackSize":64,"unlocalizedName":"block.minecraft.pumpkin"},{"id":"minecraft:pumpkin_pie","localizedName":"Pumpkin Pie","maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_pie"},{"id":"minecraft:pumpkin_seeds","localizedName":"Pumpkin Seeds","maxStackSize":64,"unlocalizedName":"item.minecraft.pumpkin_seeds"},{"id":"minecraft:purple_banner","localizedName":"Purple Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.purple_banner"},{"id":"minecraft:purple_bed","localizedName":"Purple Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.purple_bed"},{"id":"minecraft:purple_bundle","localizedName":"Purple Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.purple_bundle"},{"id":"minecraft:purple_candle","localizedName":"Purple Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_candle"},{"id":"minecraft:purple_carpet","localizedName":"Purple Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_carpet"},{"id":"minecraft:purple_concrete","localizedName":"Purple Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete"},{"id":"minecraft:purple_concrete_powder","localizedName":"Purple Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_concrete_powder"},{"id":"minecraft:purple_dye","localizedName":"Purple Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.purple_dye"},{"id":"minecraft:purple_glazed_terracotta","localizedName":"Purple Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_glazed_terracotta"},{"id":"minecraft:purple_shulker_box","localizedName":"Purple Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.purple_shulker_box"},{"id":"minecraft:purple_stained_glass","localizedName":"Purple Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass"},{"id":"minecraft:purple_stained_glass_pane","localizedName":"Purple Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_stained_glass_pane"},{"id":"minecraft:purple_terracotta","localizedName":"Purple Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_terracotta"},{"id":"minecraft:purple_wool","localizedName":"Purple Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.purple_wool"},{"id":"minecraft:purpur_block","localizedName":"Purpur Block","maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_block"},{"id":"minecraft:purpur_pillar","localizedName":"Purpur Pillar","maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_pillar"},{"id":"minecraft:purpur_slab","localizedName":"Purpur Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_slab"},{"id":"minecraft:purpur_stairs","localizedName":"Purpur Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.purpur_stairs"},{"id":"minecraft:quartz","localizedName":"Nether Quartz","maxStackSize":64,"unlocalizedName":"item.minecraft.quartz"},{"id":"minecraft:quartz_block","localizedName":"Block of Quartz","maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_block"},{"id":"minecraft:quartz_bricks","localizedName":"Quartz Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_bricks"},{"id":"minecraft:quartz_pillar","localizedName":"Quartz Pillar","maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_pillar"},{"id":"minecraft:quartz_slab","localizedName":"Quartz Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_slab"},{"id":"minecraft:quartz_stairs","localizedName":"Quartz Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.quartz_stairs"},{"id":"minecraft:rabbit","localizedName":"Raw Rabbit","maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit"},{"id":"minecraft:rabbit_foot","localizedName":"Rabbit\u0027s Foot","maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_foot"},{"id":"minecraft:rabbit_hide","localizedName":"Rabbit Hide","maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_hide"},{"id":"minecraft:rabbit_spawn_egg","localizedName":"Rabbit Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.rabbit_spawn_egg"},{"id":"minecraft:rabbit_stew","localizedName":"Rabbit Stew","maxStackSize":1,"unlocalizedName":"item.minecraft.rabbit_stew"},{"id":"minecraft:rail","localizedName":"Rail","maxStackSize":64,"unlocalizedName":"block.minecraft.rail"},{"id":"minecraft:raiser_armor_trim_smithing_template","localizedName":"Raiser Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.raiser_armor_trim_smithing_template"},{"id":"minecraft:ravager_spawn_egg","localizedName":"Ravager Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.ravager_spawn_egg"},{"id":"minecraft:raw_copper","localizedName":"Raw Copper","maxStackSize":64,"unlocalizedName":"item.minecraft.raw_copper"},{"id":"minecraft:raw_copper_block","localizedName":"Block of Raw Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.raw_copper_block"},{"id":"minecraft:raw_gold","localizedName":"Raw Gold","maxStackSize":64,"unlocalizedName":"item.minecraft.raw_gold"},{"id":"minecraft:raw_gold_block","localizedName":"Block of Raw Gold","maxStackSize":64,"unlocalizedName":"block.minecraft.raw_gold_block"},{"id":"minecraft:raw_iron","localizedName":"Raw Iron","maxStackSize":64,"unlocalizedName":"item.minecraft.raw_iron"},{"id":"minecraft:raw_iron_block","localizedName":"Block of Raw Iron","maxStackSize":64,"unlocalizedName":"block.minecraft.raw_iron_block"},{"id":"minecraft:recovery_compass","localizedName":"Recovery Compass","maxStackSize":64,"unlocalizedName":"item.minecraft.recovery_compass"},{"id":"minecraft:red_banner","localizedName":"Red Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.red_banner"},{"id":"minecraft:red_bed","localizedName":"Red Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.red_bed"},{"id":"minecraft:red_bundle","localizedName":"Red Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.red_bundle"},{"id":"minecraft:red_candle","localizedName":"Red Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.red_candle"},{"id":"minecraft:red_carpet","localizedName":"Red Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.red_carpet"},{"id":"minecraft:red_concrete","localizedName":"Red Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete"},{"id":"minecraft:red_concrete_powder","localizedName":"Red Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.red_concrete_powder"},{"id":"minecraft:red_dye","localizedName":"Red Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.red_dye"},{"id":"minecraft:red_glazed_terracotta","localizedName":"Red Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.red_glazed_terracotta"},{"id":"minecraft:red_mushroom","localizedName":"Red Mushroom","maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom"},{"id":"minecraft:red_mushroom_block","localizedName":"Red Mushroom Block","maxStackSize":64,"unlocalizedName":"block.minecraft.red_mushroom_block"},{"id":"minecraft:red_nether_brick_slab","localizedName":"Red Nether Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_slab"},{"id":"minecraft:red_nether_brick_stairs","localizedName":"Red Nether Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_stairs"},{"id":"minecraft:red_nether_brick_wall","localizedName":"Red Nether Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_brick_wall"},{"id":"minecraft:red_nether_bricks","localizedName":"Red Nether Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.red_nether_bricks"},{"id":"minecraft:red_sand","localizedName":"Red Sand","maxStackSize":64,"unlocalizedName":"block.minecraft.red_sand"},{"id":"minecraft:red_sandstone","localizedName":"Red Sandstone","maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone"},{"id":"minecraft:red_sandstone_slab","localizedName":"Red Sandstone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_slab"},{"id":"minecraft:red_sandstone_stairs","localizedName":"Red Sandstone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_stairs"},{"id":"minecraft:red_sandstone_wall","localizedName":"Red Sandstone Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.red_sandstone_wall"},{"id":"minecraft:red_shulker_box","localizedName":"Red Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.red_shulker_box"},{"id":"minecraft:red_stained_glass","localizedName":"Red Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass"},{"id":"minecraft:red_stained_glass_pane","localizedName":"Red Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.red_stained_glass_pane"},{"id":"minecraft:red_terracotta","localizedName":"Red Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.red_terracotta"},{"id":"minecraft:red_tulip","localizedName":"Red Tulip","maxStackSize":64,"unlocalizedName":"block.minecraft.red_tulip"},{"id":"minecraft:red_wool","localizedName":"Red Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.red_wool"},{"id":"minecraft:redstone","localizedName":"Redstone Dust","maxStackSize":64,"unlocalizedName":"item.minecraft.redstone"},{"id":"minecraft:redstone_block","localizedName":"Block of Redstone","maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_block"},{"id":"minecraft:redstone_lamp","localizedName":"Redstone Lamp","maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_lamp"},{"id":"minecraft:redstone_ore","localizedName":"Redstone Ore","maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_ore"},{"id":"minecraft:redstone_torch","localizedName":"Redstone Torch","maxStackSize":64,"unlocalizedName":"block.minecraft.redstone_torch"},{"id":"minecraft:reinforced_deepslate","localizedName":"Reinforced Deepslate","maxStackSize":64,"unlocalizedName":"block.minecraft.reinforced_deepslate"},{"id":"minecraft:repeater","localizedName":"Redstone Repeater","maxStackSize":64,"unlocalizedName":"block.minecraft.repeater"},{"id":"minecraft:repeating_command_block","localizedName":"Repeating Command Block","maxStackSize":64,"unlocalizedName":"block.minecraft.repeating_command_block"},{"id":"minecraft:respawn_anchor","localizedName":"Respawn Anchor","maxStackSize":64,"unlocalizedName":"block.minecraft.respawn_anchor"},{"id":"minecraft:rib_armor_trim_smithing_template","localizedName":"Rib Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.rib_armor_trim_smithing_template"},{"id":"minecraft:rooted_dirt","localizedName":"Rooted Dirt","maxStackSize":64,"unlocalizedName":"block.minecraft.rooted_dirt"},{"id":"minecraft:rose_bush","localizedName":"Rose Bush","maxStackSize":64,"unlocalizedName":"block.minecraft.rose_bush"},{"id":"minecraft:rotten_flesh","localizedName":"Rotten Flesh","maxStackSize":64,"unlocalizedName":"item.minecraft.rotten_flesh"},{"id":"minecraft:saddle","localizedName":"Saddle","maxStackSize":1,"unlocalizedName":"item.minecraft.saddle"},{"id":"minecraft:salmon","localizedName":"Raw Salmon","maxStackSize":64,"unlocalizedName":"item.minecraft.salmon"},{"id":"minecraft:salmon_bucket","localizedName":"Bucket of Salmon","maxStackSize":1,"unlocalizedName":"item.minecraft.salmon_bucket"},{"id":"minecraft:salmon_spawn_egg","localizedName":"Salmon Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.salmon_spawn_egg"},{"id":"minecraft:sand","localizedName":"Sand","maxStackSize":64,"unlocalizedName":"block.minecraft.sand"},{"id":"minecraft:sandstone","localizedName":"Sandstone","maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone"},{"id":"minecraft:sandstone_slab","localizedName":"Sandstone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_slab"},{"id":"minecraft:sandstone_stairs","localizedName":"Sandstone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_stairs"},{"id":"minecraft:sandstone_wall","localizedName":"Sandstone Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.sandstone_wall"},{"id":"minecraft:scaffolding","localizedName":"Scaffolding","maxStackSize":64,"unlocalizedName":"block.minecraft.scaffolding"},{"id":"minecraft:scrape_pottery_sherd","localizedName":"Scrape Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.scrape_pottery_sherd"},{"id":"minecraft:sculk","localizedName":"Sculk","maxStackSize":64,"unlocalizedName":"block.minecraft.sculk"},{"id":"minecraft:sculk_catalyst","localizedName":"Sculk Catalyst","maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_catalyst"},{"id":"minecraft:sculk_sensor","localizedName":"Sculk Sensor","maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_sensor"},{"id":"minecraft:sculk_shrieker","localizedName":"Sculk Shrieker","maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_shrieker"},{"id":"minecraft:sculk_vein","localizedName":"Sculk Vein","maxStackSize":64,"unlocalizedName":"block.minecraft.sculk_vein"},{"id":"minecraft:sea_lantern","localizedName":"Sea Lantern","maxStackSize":64,"unlocalizedName":"block.minecraft.sea_lantern"},{"id":"minecraft:sea_pickle","localizedName":"Sea Pickle","maxStackSize":64,"unlocalizedName":"block.minecraft.sea_pickle"},{"id":"minecraft:seagrass","localizedName":"Seagrass","maxStackSize":64,"unlocalizedName":"block.minecraft.seagrass"},{"id":"minecraft:sentry_armor_trim_smithing_template","localizedName":"Sentry Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.sentry_armor_trim_smithing_template"},{"id":"minecraft:shaper_armor_trim_smithing_template","localizedName":"Shaper Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.shaper_armor_trim_smithing_template"},{"id":"minecraft:sheaf_pottery_sherd","localizedName":"Sheaf Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.sheaf_pottery_sherd"},{"id":"minecraft:shears","localizedName":"Shears","maxDamage":238,"maxStackSize":1,"unlocalizedName":"item.minecraft.shears"},{"id":"minecraft:sheep_spawn_egg","localizedName":"Sheep Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.sheep_spawn_egg"},{"id":"minecraft:shelter_pottery_sherd","localizedName":"Shelter Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.shelter_pottery_sherd"},{"id":"minecraft:shield","localizedName":"Shield","maxDamage":336,"maxStackSize":1,"unlocalizedName":"item.minecraft.shield"},{"id":"minecraft:short_grass","localizedName":"Short Grass","maxStackSize":64,"unlocalizedName":"block.minecraft.short_grass"},{"id":"minecraft:shroomlight","localizedName":"Shroomlight","maxStackSize":64,"unlocalizedName":"block.minecraft.shroomlight"},{"id":"minecraft:shulker_box","localizedName":"Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.shulker_box"},{"id":"minecraft:shulker_shell","localizedName":"Shulker Shell","maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_shell"},{"id":"minecraft:shulker_spawn_egg","localizedName":"Shulker Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.shulker_spawn_egg"},{"id":"minecraft:silence_armor_trim_smithing_template","localizedName":"Silence Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.silence_armor_trim_smithing_template"},{"id":"minecraft:silverfish_spawn_egg","localizedName":"Silverfish Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.silverfish_spawn_egg"},{"id":"minecraft:skeleton_horse_spawn_egg","localizedName":"Skeleton Horse Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_horse_spawn_egg"},{"id":"minecraft:skeleton_skull","localizedName":"Skeleton Skull","maxStackSize":64,"unlocalizedName":"block.minecraft.skeleton_skull"},{"id":"minecraft:skeleton_spawn_egg","localizedName":"Skeleton Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.skeleton_spawn_egg"},{"id":"minecraft:skull_banner_pattern","localizedName":"Skull Charge Banner Pattern","maxStackSize":1,"unlocalizedName":"item.minecraft.skull_banner_pattern"},{"id":"minecraft:skull_pottery_sherd","localizedName":"Skull Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.skull_pottery_sherd"},{"id":"minecraft:slime_ball","localizedName":"Slimeball","maxStackSize":64,"unlocalizedName":"item.minecraft.slime_ball"},{"id":"minecraft:slime_block","localizedName":"Slime Block","maxStackSize":64,"unlocalizedName":"block.minecraft.slime_block"},{"id":"minecraft:slime_spawn_egg","localizedName":"Slime Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.slime_spawn_egg"},{"id":"minecraft:small_amethyst_bud","localizedName":"Small Amethyst Bud","maxStackSize":64,"unlocalizedName":"block.minecraft.small_amethyst_bud"},{"id":"minecraft:small_dripleaf","localizedName":"Small Dripleaf","maxStackSize":64,"unlocalizedName":"block.minecraft.small_dripleaf"},{"id":"minecraft:smithing_table","localizedName":"Smithing Table","maxStackSize":64,"unlocalizedName":"block.minecraft.smithing_table"},{"id":"minecraft:smoker","localizedName":"Smoker","maxStackSize":64,"unlocalizedName":"block.minecraft.smoker"},{"id":"minecraft:smooth_basalt","localizedName":"Smooth Basalt","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_basalt"},{"id":"minecraft:smooth_quartz","localizedName":"Smooth Quartz Block","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz"},{"id":"minecraft:smooth_quartz_slab","localizedName":"Smooth Quartz Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_slab"},{"id":"minecraft:smooth_quartz_stairs","localizedName":"Smooth Quartz Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_quartz_stairs"},{"id":"minecraft:smooth_red_sandstone","localizedName":"Smooth Red Sandstone","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone"},{"id":"minecraft:smooth_red_sandstone_slab","localizedName":"Smooth Red Sandstone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_slab"},{"id":"minecraft:smooth_red_sandstone_stairs","localizedName":"Smooth Red Sandstone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_red_sandstone_stairs"},{"id":"minecraft:smooth_sandstone","localizedName":"Smooth Sandstone","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone"},{"id":"minecraft:smooth_sandstone_slab","localizedName":"Smooth Sandstone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_slab"},{"id":"minecraft:smooth_sandstone_stairs","localizedName":"Smooth Sandstone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_sandstone_stairs"},{"id":"minecraft:smooth_stone","localizedName":"Smooth Stone","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone"},{"id":"minecraft:smooth_stone_slab","localizedName":"Smooth Stone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.smooth_stone_slab"},{"id":"minecraft:sniffer_egg","localizedName":"Sniffer Egg","maxStackSize":64,"unlocalizedName":"block.minecraft.sniffer_egg"},{"id":"minecraft:sniffer_spawn_egg","localizedName":"Sniffer Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.sniffer_spawn_egg"},{"id":"minecraft:snort_pottery_sherd","localizedName":"Snort Pottery Sherd","maxStackSize":64,"unlocalizedName":"item.minecraft.snort_pottery_sherd"},{"id":"minecraft:snout_armor_trim_smithing_template","localizedName":"Snout Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.snout_armor_trim_smithing_template"},{"id":"minecraft:snow","localizedName":"Snow","maxStackSize":64,"unlocalizedName":"block.minecraft.snow"},{"id":"minecraft:snow_block","localizedName":"Snow Block","maxStackSize":64,"unlocalizedName":"block.minecraft.snow_block"},{"id":"minecraft:snow_golem_spawn_egg","localizedName":"Snow Golem Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.snow_golem_spawn_egg"},{"id":"minecraft:snowball","localizedName":"Snowball","maxStackSize":16,"unlocalizedName":"item.minecraft.snowball"},{"id":"minecraft:soul_campfire","localizedName":"Soul Campfire","maxStackSize":64,"unlocalizedName":"block.minecraft.soul_campfire"},{"id":"minecraft:soul_lantern","localizedName":"Soul Lantern","maxStackSize":64,"unlocalizedName":"block.minecraft.soul_lantern"},{"id":"minecraft:soul_sand","localizedName":"Soul Sand","maxStackSize":64,"unlocalizedName":"block.minecraft.soul_sand"},{"id":"minecraft:soul_soil","localizedName":"Soul Soil","maxStackSize":64,"unlocalizedName":"block.minecraft.soul_soil"},{"id":"minecraft:soul_torch","localizedName":"Soul Torch","maxStackSize":64,"unlocalizedName":"block.minecraft.soul_torch"},{"id":"minecraft:spawner","localizedName":"Monster Spawner","maxStackSize":64,"unlocalizedName":"block.minecraft.spawner"},{"id":"minecraft:spectral_arrow","localizedName":"Spectral Arrow","maxStackSize":64,"unlocalizedName":"item.minecraft.spectral_arrow"},{"id":"minecraft:spider_eye","localizedName":"Spider Eye","maxStackSize":64,"unlocalizedName":"item.minecraft.spider_eye"},{"id":"minecraft:spider_spawn_egg","localizedName":"Spider Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.spider_spawn_egg"},{"id":"minecraft:spire_armor_trim_smithing_template","localizedName":"Spire Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.spire_armor_trim_smithing_template"},{"id":"minecraft:splash_potion","localizedName":"Splash Water Bottle","maxStackSize":1,"unlocalizedName":"item.minecraft.splash_potion"},{"id":"minecraft:sponge","localizedName":"Sponge","maxStackSize":64,"unlocalizedName":"block.minecraft.sponge"},{"id":"minecraft:spore_blossom","localizedName":"Spore Blossom","maxStackSize":64,"unlocalizedName":"block.minecraft.spore_blossom"},{"id":"minecraft:spruce_boat","localizedName":"Spruce Boat","maxStackSize":1,"unlocalizedName":"item.minecraft.spruce_boat"},{"id":"minecraft:spruce_button","localizedName":"Spruce Button","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_button"},{"id":"minecraft:spruce_chest_boat","localizedName":"Spruce Boat with Chest","maxStackSize":1,"unlocalizedName":"item.minecraft.spruce_chest_boat"},{"id":"minecraft:spruce_door","localizedName":"Spruce Door","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_door"},{"id":"minecraft:spruce_fence","localizedName":"Spruce Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence"},{"id":"minecraft:spruce_fence_gate","localizedName":"Spruce Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_fence_gate"},{"id":"minecraft:spruce_hanging_sign","localizedName":"Spruce Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.spruce_hanging_sign"},{"id":"minecraft:spruce_leaves","localizedName":"Spruce Leaves","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_leaves"},{"id":"minecraft:spruce_log","localizedName":"Spruce Log","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_log"},{"id":"minecraft:spruce_planks","localizedName":"Spruce Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_planks"},{"id":"minecraft:spruce_pressure_plate","localizedName":"Spruce Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_pressure_plate"},{"id":"minecraft:spruce_sapling","localizedName":"Spruce Sapling","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_sapling"},{"id":"minecraft:spruce_sign","localizedName":"Spruce Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.spruce_sign"},{"id":"minecraft:spruce_slab","localizedName":"Spruce Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_slab"},{"id":"minecraft:spruce_stairs","localizedName":"Spruce Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_stairs"},{"id":"minecraft:spruce_trapdoor","localizedName":"Spruce Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_trapdoor"},{"id":"minecraft:spruce_wood","localizedName":"Spruce Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.spruce_wood"},{"id":"minecraft:spyglass","localizedName":"Spyglass","maxStackSize":1,"unlocalizedName":"item.minecraft.spyglass"},{"id":"minecraft:squid_spawn_egg","localizedName":"Squid Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.squid_spawn_egg"},{"id":"minecraft:stick","localizedName":"Stick","maxStackSize":64,"unlocalizedName":"item.minecraft.stick"},{"id":"minecraft:sticky_piston","localizedName":"Sticky Piston","maxStackSize":64,"unlocalizedName":"block.minecraft.sticky_piston"},{"id":"minecraft:stone","localizedName":"Stone","maxStackSize":64,"unlocalizedName":"block.minecraft.stone"},{"id":"minecraft:stone_axe","localizedName":"Stone Axe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_axe"},{"id":"minecraft:stone_brick_slab","localizedName":"Stone Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_slab"},{"id":"minecraft:stone_brick_stairs","localizedName":"Stone Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_stairs"},{"id":"minecraft:stone_brick_wall","localizedName":"Stone Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.stone_brick_wall"},{"id":"minecraft:stone_bricks","localizedName":"Stone Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.stone_bricks"},{"id":"minecraft:stone_button","localizedName":"Stone Button","maxStackSize":64,"unlocalizedName":"block.minecraft.stone_button"},{"id":"minecraft:stone_hoe","localizedName":"Stone Hoe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_hoe"},{"id":"minecraft:stone_pickaxe","localizedName":"Stone Pickaxe","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_pickaxe"},{"id":"minecraft:stone_pressure_plate","localizedName":"Stone Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.stone_pressure_plate"},{"id":"minecraft:stone_shovel","localizedName":"Stone Shovel","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_shovel"},{"id":"minecraft:stone_slab","localizedName":"Stone Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.stone_slab"},{"id":"minecraft:stone_stairs","localizedName":"Stone Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.stone_stairs"},{"id":"minecraft:stone_sword","localizedName":"Stone Sword","maxDamage":131,"maxStackSize":1,"unlocalizedName":"item.minecraft.stone_sword"},{"id":"minecraft:stonecutter","localizedName":"Stonecutter","maxStackSize":64,"unlocalizedName":"block.minecraft.stonecutter"},{"id":"minecraft:stray_spawn_egg","localizedName":"Stray Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.stray_spawn_egg"},{"id":"minecraft:strider_spawn_egg","localizedName":"Strider Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.strider_spawn_egg"},{"id":"minecraft:string","localizedName":"String","maxStackSize":64,"unlocalizedName":"item.minecraft.string"},{"id":"minecraft:stripped_acacia_log","localizedName":"Stripped Acacia Log","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_log"},{"id":"minecraft:stripped_acacia_wood","localizedName":"Stripped Acacia Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_acacia_wood"},{"id":"minecraft:stripped_bamboo_block","localizedName":"Block of Stripped Bamboo","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_bamboo_block"},{"id":"minecraft:stripped_birch_log","localizedName":"Stripped Birch Log","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_log"},{"id":"minecraft:stripped_birch_wood","localizedName":"Stripped Birch Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_birch_wood"},{"id":"minecraft:stripped_cherry_log","localizedName":"Stripped Cherry Log","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_cherry_log"},{"id":"minecraft:stripped_cherry_wood","localizedName":"Stripped Cherry Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_cherry_wood"},{"id":"minecraft:stripped_crimson_hyphae","localizedName":"Stripped Crimson Hyphae","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_hyphae"},{"id":"minecraft:stripped_crimson_stem","localizedName":"Stripped Crimson Stem","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_crimson_stem"},{"id":"minecraft:stripped_dark_oak_log","localizedName":"Stripped Dark Oak Log","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_log"},{"id":"minecraft:stripped_dark_oak_wood","localizedName":"Stripped Dark Oak Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_dark_oak_wood"},{"id":"minecraft:stripped_jungle_log","localizedName":"Stripped Jungle Log","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_log"},{"id":"minecraft:stripped_jungle_wood","localizedName":"Stripped Jungle Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_jungle_wood"},{"id":"minecraft:stripped_mangrove_log","localizedName":"Stripped Mangrove Log","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_mangrove_log"},{"id":"minecraft:stripped_mangrove_wood","localizedName":"Stripped Mangrove Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_mangrove_wood"},{"id":"minecraft:stripped_oak_log","localizedName":"Stripped Oak Log","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_log"},{"id":"minecraft:stripped_oak_wood","localizedName":"Stripped Oak Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_oak_wood"},{"id":"minecraft:stripped_pale_oak_log","localizedName":"Stripped Pale Oak Log","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_pale_oak_log"},{"id":"minecraft:stripped_pale_oak_wood","localizedName":"Stripped Pale Oak Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_pale_oak_wood"},{"id":"minecraft:stripped_spruce_log","localizedName":"Stripped Spruce Log","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_log"},{"id":"minecraft:stripped_spruce_wood","localizedName":"Stripped Spruce Wood","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_spruce_wood"},{"id":"minecraft:stripped_warped_hyphae","localizedName":"Stripped Warped Hyphae","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_hyphae"},{"id":"minecraft:stripped_warped_stem","localizedName":"Stripped Warped Stem","maxStackSize":64,"unlocalizedName":"block.minecraft.stripped_warped_stem"},{"id":"minecraft:structure_block","localizedName":"Structure Block","maxStackSize":64,"unlocalizedName":"block.minecraft.structure_block"},{"id":"minecraft:structure_void","localizedName":"Structure Void","maxStackSize":64,"unlocalizedName":"block.minecraft.structure_void"},{"id":"minecraft:sugar","localizedName":"Sugar","maxStackSize":64,"unlocalizedName":"item.minecraft.sugar"},{"id":"minecraft:sugar_cane","localizedName":"Sugar Cane","maxStackSize":64,"unlocalizedName":"block.minecraft.sugar_cane"},{"id":"minecraft:sunflower","localizedName":"Sunflower","maxStackSize":64,"unlocalizedName":"block.minecraft.sunflower"},{"id":"minecraft:suspicious_gravel","localizedName":"Suspicious Gravel","maxStackSize":64,"unlocalizedName":"block.minecraft.suspicious_gravel"},{"id":"minecraft:suspicious_sand","localizedName":"Suspicious Sand","maxStackSize":64,"unlocalizedName":"block.minecraft.suspicious_sand"},{"id":"minecraft:suspicious_stew","localizedName":"Suspicious Stew","maxStackSize":1,"unlocalizedName":"item.minecraft.suspicious_stew"},{"id":"minecraft:sweet_berries","localizedName":"Sweet Berries","maxStackSize":64,"unlocalizedName":"item.minecraft.sweet_berries"},{"id":"minecraft:tadpole_bucket","localizedName":"Bucket of Tadpole","maxStackSize":1,"unlocalizedName":"item.minecraft.tadpole_bucket"},{"id":"minecraft:tadpole_spawn_egg","localizedName":"Tadpole Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.tadpole_spawn_egg"},{"id":"minecraft:tall_grass","localizedName":"Tall Grass","maxStackSize":64,"unlocalizedName":"block.minecraft.tall_grass"},{"id":"minecraft:target","localizedName":"Target","maxStackSize":64,"unlocalizedName":"block.minecraft.target"},{"id":"minecraft:terracotta","localizedName":"Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.terracotta"},{"id":"minecraft:tide_armor_trim_smithing_template","localizedName":"Tide Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.tide_armor_trim_smithing_template"},{"id":"minecraft:tinted_glass","localizedName":"Tinted Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.tinted_glass"},{"id":"minecraft:tipped_arrow","localizedName":"Arrow of Poison","maxStackSize":64,"unlocalizedName":"item.minecraft.tipped_arrow"},{"id":"minecraft:tnt","localizedName":"TNT","maxStackSize":64,"unlocalizedName":"block.minecraft.tnt"},{"id":"minecraft:tnt_minecart","localizedName":"Minecart with TNT","maxStackSize":1,"unlocalizedName":"item.minecraft.tnt_minecart"},{"id":"minecraft:torch","localizedName":"Torch","maxStackSize":64,"unlocalizedName":"block.minecraft.torch"},{"id":"minecraft:torchflower","localizedName":"Torchflower","maxStackSize":64,"unlocalizedName":"block.minecraft.torchflower"},{"id":"minecraft:torchflower_seeds","localizedName":"Torchflower Seeds","maxStackSize":64,"unlocalizedName":"item.minecraft.torchflower_seeds"},{"id":"minecraft:totem_of_undying","localizedName":"Totem of Undying","maxStackSize":1,"unlocalizedName":"item.minecraft.totem_of_undying"},{"id":"minecraft:trader_llama_spawn_egg","localizedName":"Trader Llama Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.trader_llama_spawn_egg"},{"id":"minecraft:trapped_chest","localizedName":"Trapped Chest","maxStackSize":64,"unlocalizedName":"block.minecraft.trapped_chest"},{"id":"minecraft:trial_key","localizedName":"Trial Key","maxStackSize":64,"unlocalizedName":"item.minecraft.trial_key"},{"id":"minecraft:trial_spawner","localizedName":"Trial Spawner","maxStackSize":64,"unlocalizedName":"block.minecraft.trial_spawner"},{"id":"minecraft:trident","localizedName":"Trident","maxDamage":250,"maxStackSize":1,"unlocalizedName":"item.minecraft.trident"},{"id":"minecraft:tripwire_hook","localizedName":"Tripwire Hook","maxStackSize":64,"unlocalizedName":"block.minecraft.tripwire_hook"},{"id":"minecraft:tropical_fish","localizedName":"Tropical Fish","maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish"},{"id":"minecraft:tropical_fish_bucket","localizedName":"Bucket of Tropical Fish","maxStackSize":1,"unlocalizedName":"item.minecraft.tropical_fish_bucket"},{"id":"minecraft:tropical_fish_spawn_egg","localizedName":"Tropical Fish Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.tropical_fish_spawn_egg"},{"id":"minecraft:tube_coral","localizedName":"Tube Coral","maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral"},{"id":"minecraft:tube_coral_block","localizedName":"Tube Coral Block","maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_block"},{"id":"minecraft:tube_coral_fan","localizedName":"Tube Coral Fan","maxStackSize":64,"unlocalizedName":"block.minecraft.tube_coral_fan"},{"id":"minecraft:tuff","localizedName":"Tuff","maxStackSize":64,"unlocalizedName":"block.minecraft.tuff"},{"id":"minecraft:tuff_brick_slab","localizedName":"Tuff Brick Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.tuff_brick_slab"},{"id":"minecraft:tuff_brick_stairs","localizedName":"Tuff Brick Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.tuff_brick_stairs"},{"id":"minecraft:tuff_brick_wall","localizedName":"Tuff Brick Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.tuff_brick_wall"},{"id":"minecraft:tuff_bricks","localizedName":"Tuff Bricks","maxStackSize":64,"unlocalizedName":"block.minecraft.tuff_bricks"},{"id":"minecraft:tuff_slab","localizedName":"Tuff Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.tuff_slab"},{"id":"minecraft:tuff_stairs","localizedName":"Tuff Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.tuff_stairs"},{"id":"minecraft:tuff_wall","localizedName":"Tuff Wall","maxStackSize":64,"unlocalizedName":"block.minecraft.tuff_wall"},{"id":"minecraft:turtle_egg","localizedName":"Turtle Egg","maxStackSize":64,"unlocalizedName":"block.minecraft.turtle_egg"},{"id":"minecraft:turtle_helmet","localizedName":"Turtle Shell","maxDamage":275,"maxStackSize":1,"unlocalizedName":"item.minecraft.turtle_helmet"},{"id":"minecraft:turtle_scute","localizedName":"Turtle Scute","maxStackSize":64,"unlocalizedName":"item.minecraft.turtle_scute"},{"id":"minecraft:turtle_spawn_egg","localizedName":"Turtle Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.turtle_spawn_egg"},{"id":"minecraft:twisting_vines","localizedName":"Twisting Vines","maxStackSize":64,"unlocalizedName":"block.minecraft.twisting_vines"},{"id":"minecraft:vault","localizedName":"Vault","maxStackSize":64,"unlocalizedName":"block.minecraft.vault"},{"id":"minecraft:verdant_froglight","localizedName":"Verdant Froglight","maxStackSize":64,"unlocalizedName":"block.minecraft.verdant_froglight"},{"id":"minecraft:vex_armor_trim_smithing_template","localizedName":"Vex Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.vex_armor_trim_smithing_template"},{"id":"minecraft:vex_spawn_egg","localizedName":"Vex Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.vex_spawn_egg"},{"id":"minecraft:villager_spawn_egg","localizedName":"Villager Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.villager_spawn_egg"},{"id":"minecraft:vindicator_spawn_egg","localizedName":"Vindicator Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.vindicator_spawn_egg"},{"id":"minecraft:vine","localizedName":"Vines","maxStackSize":64,"unlocalizedName":"block.minecraft.vine"},{"id":"minecraft:wandering_trader_spawn_egg","localizedName":"Wandering Trader Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.wandering_trader_spawn_egg"},{"id":"minecraft:ward_armor_trim_smithing_template","localizedName":"Ward Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.ward_armor_trim_smithing_template"},{"id":"minecraft:warden_spawn_egg","localizedName":"Warden Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.warden_spawn_egg"},{"id":"minecraft:warped_button","localizedName":"Warped Button","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_button"},{"id":"minecraft:warped_door","localizedName":"Warped Door","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_door"},{"id":"minecraft:warped_fence","localizedName":"Warped Fence","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence"},{"id":"minecraft:warped_fence_gate","localizedName":"Warped Fence Gate","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fence_gate"},{"id":"minecraft:warped_fungus","localizedName":"Warped Fungus","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_fungus"},{"id":"minecraft:warped_fungus_on_a_stick","localizedName":"Warped Fungus on a Stick","maxDamage":100,"maxStackSize":1,"unlocalizedName":"item.minecraft.warped_fungus_on_a_stick"},{"id":"minecraft:warped_hanging_sign","localizedName":"Warped Hanging Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.warped_hanging_sign"},{"id":"minecraft:warped_hyphae","localizedName":"Warped Hyphae","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_hyphae"},{"id":"minecraft:warped_nylium","localizedName":"Warped Nylium","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_nylium"},{"id":"minecraft:warped_planks","localizedName":"Warped Planks","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_planks"},{"id":"minecraft:warped_pressure_plate","localizedName":"Warped Pressure Plate","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_pressure_plate"},{"id":"minecraft:warped_roots","localizedName":"Warped Roots","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_roots"},{"id":"minecraft:warped_sign","localizedName":"Warped Sign","maxStackSize":16,"unlocalizedName":"block.minecraft.warped_sign"},{"id":"minecraft:warped_slab","localizedName":"Warped Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_slab"},{"id":"minecraft:warped_stairs","localizedName":"Warped Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stairs"},{"id":"minecraft:warped_stem","localizedName":"Warped Stem","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_stem"},{"id":"minecraft:warped_trapdoor","localizedName":"Warped Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_trapdoor"},{"id":"minecraft:warped_wart_block","localizedName":"Warped Wart Block","maxStackSize":64,"unlocalizedName":"block.minecraft.warped_wart_block"},{"id":"minecraft:water_bucket","localizedName":"Water Bucket","maxStackSize":1,"unlocalizedName":"item.minecraft.water_bucket"},{"id":"minecraft:waxed_chiseled_copper","localizedName":"Waxed Chiseled Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_chiseled_copper"},{"id":"minecraft:waxed_copper_block","localizedName":"Waxed Block of Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_copper_block"},{"id":"minecraft:waxed_copper_bulb","localizedName":"Waxed Copper Bulb","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_copper_bulb"},{"id":"minecraft:waxed_copper_door","localizedName":"Waxed Copper Door","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_copper_door"},{"id":"minecraft:waxed_copper_grate","localizedName":"Waxed Copper Grate","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_copper_grate"},{"id":"minecraft:waxed_copper_trapdoor","localizedName":"Waxed Copper Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_copper_trapdoor"},{"id":"minecraft:waxed_cut_copper","localizedName":"Waxed Cut Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper"},{"id":"minecraft:waxed_cut_copper_slab","localizedName":"Waxed Cut Copper Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper_slab"},{"id":"minecraft:waxed_cut_copper_stairs","localizedName":"Waxed Cut Copper Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_cut_copper_stairs"},{"id":"minecraft:waxed_exposed_chiseled_copper","localizedName":"Waxed Exposed Chiseled Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_chiseled_copper"},{"id":"minecraft:waxed_exposed_copper","localizedName":"Waxed Exposed Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_copper"},{"id":"minecraft:waxed_exposed_copper_bulb","localizedName":"Waxed Exposed Copper Bulb","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_copper_bulb"},{"id":"minecraft:waxed_exposed_copper_door","localizedName":"Waxed Exposed Copper Door","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_copper_door"},{"id":"minecraft:waxed_exposed_copper_grate","localizedName":"Waxed Exposed Copper Grate","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_copper_grate"},{"id":"minecraft:waxed_exposed_copper_trapdoor","localizedName":"Waxed Exposed Copper Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_copper_trapdoor"},{"id":"minecraft:waxed_exposed_cut_copper","localizedName":"Waxed Exposed Cut Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper"},{"id":"minecraft:waxed_exposed_cut_copper_slab","localizedName":"Waxed Exposed Cut Copper Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper_slab"},{"id":"minecraft:waxed_exposed_cut_copper_stairs","localizedName":"Waxed Exposed Cut Copper Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_exposed_cut_copper_stairs"},{"id":"minecraft:waxed_oxidized_chiseled_copper","localizedName":"Waxed Oxidized Chiseled Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_chiseled_copper"},{"id":"minecraft:waxed_oxidized_copper","localizedName":"Waxed Oxidized Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_copper"},{"id":"minecraft:waxed_oxidized_copper_bulb","localizedName":"Waxed Oxidized Copper Bulb","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_copper_bulb"},{"id":"minecraft:waxed_oxidized_copper_door","localizedName":"Waxed Oxidized Copper Door","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_copper_door"},{"id":"minecraft:waxed_oxidized_copper_grate","localizedName":"Waxed Oxidized Copper Grate","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_copper_grate"},{"id":"minecraft:waxed_oxidized_copper_trapdoor","localizedName":"Waxed Oxidized Copper Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_copper_trapdoor"},{"id":"minecraft:waxed_oxidized_cut_copper","localizedName":"Waxed Oxidized Cut Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper"},{"id":"minecraft:waxed_oxidized_cut_copper_slab","localizedName":"Waxed Oxidized Cut Copper Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper_slab"},{"id":"minecraft:waxed_oxidized_cut_copper_stairs","localizedName":"Waxed Oxidized Cut Copper Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_oxidized_cut_copper_stairs"},{"id":"minecraft:waxed_weathered_chiseled_copper","localizedName":"Waxed Weathered Chiseled Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_chiseled_copper"},{"id":"minecraft:waxed_weathered_copper","localizedName":"Waxed Weathered Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_copper"},{"id":"minecraft:waxed_weathered_copper_bulb","localizedName":"Waxed Weathered Copper Bulb","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_copper_bulb"},{"id":"minecraft:waxed_weathered_copper_door","localizedName":"Waxed Weathered Copper Door","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_copper_door"},{"id":"minecraft:waxed_weathered_copper_grate","localizedName":"Waxed Weathered Copper Grate","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_copper_grate"},{"id":"minecraft:waxed_weathered_copper_trapdoor","localizedName":"Waxed Weathered Copper Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_copper_trapdoor"},{"id":"minecraft:waxed_weathered_cut_copper","localizedName":"Waxed Weathered Cut Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper"},{"id":"minecraft:waxed_weathered_cut_copper_slab","localizedName":"Waxed Weathered Cut Copper Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper_slab"},{"id":"minecraft:waxed_weathered_cut_copper_stairs","localizedName":"Waxed Weathered Cut Copper Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.waxed_weathered_cut_copper_stairs"},{"id":"minecraft:wayfinder_armor_trim_smithing_template","localizedName":"Wayfinder Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.wayfinder_armor_trim_smithing_template"},{"id":"minecraft:weathered_chiseled_copper","localizedName":"Weathered Chiseled Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_chiseled_copper"},{"id":"minecraft:weathered_copper","localizedName":"Weathered Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_copper"},{"id":"minecraft:weathered_copper_bulb","localizedName":"Weathered Copper Bulb","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_copper_bulb"},{"id":"minecraft:weathered_copper_door","localizedName":"Weathered Copper Door","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_copper_door"},{"id":"minecraft:weathered_copper_grate","localizedName":"Weathered Copper Grate","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_copper_grate"},{"id":"minecraft:weathered_copper_trapdoor","localizedName":"Weathered Copper Trapdoor","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_copper_trapdoor"},{"id":"minecraft:weathered_cut_copper","localizedName":"Weathered Cut Copper","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper"},{"id":"minecraft:weathered_cut_copper_slab","localizedName":"Weathered Cut Copper Slab","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper_slab"},{"id":"minecraft:weathered_cut_copper_stairs","localizedName":"Weathered Cut Copper Stairs","maxStackSize":64,"unlocalizedName":"block.minecraft.weathered_cut_copper_stairs"},{"id":"minecraft:weeping_vines","localizedName":"Weeping Vines","maxStackSize":64,"unlocalizedName":"block.minecraft.weeping_vines"},{"id":"minecraft:wet_sponge","localizedName":"Wet Sponge","maxStackSize":64,"unlocalizedName":"block.minecraft.wet_sponge"},{"id":"minecraft:wheat","localizedName":"Wheat","maxStackSize":64,"unlocalizedName":"item.minecraft.wheat"},{"id":"minecraft:wheat_seeds","localizedName":"Wheat Seeds","maxStackSize":64,"unlocalizedName":"item.minecraft.wheat_seeds"},{"id":"minecraft:white_banner","localizedName":"White Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.white_banner"},{"id":"minecraft:white_bed","localizedName":"White Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.white_bed"},{"id":"minecraft:white_bundle","localizedName":"White Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.white_bundle"},{"id":"minecraft:white_candle","localizedName":"White Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.white_candle"},{"id":"minecraft:white_carpet","localizedName":"White Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.white_carpet"},{"id":"minecraft:white_concrete","localizedName":"White Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete"},{"id":"minecraft:white_concrete_powder","localizedName":"White Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.white_concrete_powder"},{"id":"minecraft:white_dye","localizedName":"White Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.white_dye"},{"id":"minecraft:white_glazed_terracotta","localizedName":"White Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.white_glazed_terracotta"},{"id":"minecraft:white_shulker_box","localizedName":"White Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.white_shulker_box"},{"id":"minecraft:white_stained_glass","localizedName":"White Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass"},{"id":"minecraft:white_stained_glass_pane","localizedName":"White Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.white_stained_glass_pane"},{"id":"minecraft:white_terracotta","localizedName":"White Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.white_terracotta"},{"id":"minecraft:white_tulip","localizedName":"White Tulip","maxStackSize":64,"unlocalizedName":"block.minecraft.white_tulip"},{"id":"minecraft:white_wool","localizedName":"White Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.white_wool"},{"id":"minecraft:wild_armor_trim_smithing_template","localizedName":"Wild Armor Trim","maxStackSize":64,"unlocalizedName":"item.minecraft.wild_armor_trim_smithing_template"},{"id":"minecraft:wind_charge","localizedName":"Wind Charge","maxStackSize":64,"unlocalizedName":"item.minecraft.wind_charge"},{"id":"minecraft:witch_spawn_egg","localizedName":"Witch Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.witch_spawn_egg"},{"id":"minecraft:wither_rose","localizedName":"Wither Rose","maxStackSize":64,"unlocalizedName":"block.minecraft.wither_rose"},{"id":"minecraft:wither_skeleton_skull","localizedName":"Wither Skeleton Skull","maxStackSize":64,"unlocalizedName":"block.minecraft.wither_skeleton_skull"},{"id":"minecraft:wither_skeleton_spawn_egg","localizedName":"Wither Skeleton Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.wither_skeleton_spawn_egg"},{"id":"minecraft:wither_spawn_egg","localizedName":"Wither Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.wither_spawn_egg"},{"id":"minecraft:wolf_armor","localizedName":"Wolf Armor","maxDamage":64,"maxStackSize":1,"unlocalizedName":"item.minecraft.wolf_armor"},{"id":"minecraft:wolf_spawn_egg","localizedName":"Wolf Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.wolf_spawn_egg"},{"id":"minecraft:wooden_axe","localizedName":"Wooden Axe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_axe"},{"id":"minecraft:wooden_hoe","localizedName":"Wooden Hoe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_hoe"},{"id":"minecraft:wooden_pickaxe","localizedName":"Wooden Pickaxe","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_pickaxe"},{"id":"minecraft:wooden_shovel","localizedName":"Wooden Shovel","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_shovel"},{"id":"minecraft:wooden_sword","localizedName":"Wooden Sword","maxDamage":59,"maxStackSize":1,"unlocalizedName":"item.minecraft.wooden_sword"},{"id":"minecraft:writable_book","localizedName":"Book and Quill","maxStackSize":1,"unlocalizedName":"item.minecraft.writable_book"},{"id":"minecraft:written_book","localizedName":"Written Book","maxStackSize":16,"unlocalizedName":"item.minecraft.written_book"},{"id":"minecraft:yellow_banner","localizedName":"Yellow Banner","maxStackSize":16,"unlocalizedName":"block.minecraft.yellow_banner"},{"id":"minecraft:yellow_bed","localizedName":"Yellow Bed","maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_bed"},{"id":"minecraft:yellow_bundle","localizedName":"Yellow Bundle","maxStackSize":1,"unlocalizedName":"item.minecraft.yellow_bundle"},{"id":"minecraft:yellow_candle","localizedName":"Yellow Candle","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_candle"},{"id":"minecraft:yellow_carpet","localizedName":"Yellow Carpet","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_carpet"},{"id":"minecraft:yellow_concrete","localizedName":"Yellow Concrete","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete"},{"id":"minecraft:yellow_concrete_powder","localizedName":"Yellow Concrete Powder","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_concrete_powder"},{"id":"minecraft:yellow_dye","localizedName":"Yellow Dye","maxStackSize":64,"unlocalizedName":"item.minecraft.yellow_dye"},{"id":"minecraft:yellow_glazed_terracotta","localizedName":"Yellow Glazed Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_glazed_terracotta"},{"id":"minecraft:yellow_shulker_box","localizedName":"Yellow Shulker Box","maxStackSize":1,"unlocalizedName":"block.minecraft.yellow_shulker_box"},{"id":"minecraft:yellow_stained_glass","localizedName":"Yellow Stained Glass","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass"},{"id":"minecraft:yellow_stained_glass_pane","localizedName":"Yellow Stained Glass Pane","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_stained_glass_pane"},{"id":"minecraft:yellow_terracotta","localizedName":"Yellow Terracotta","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_terracotta"},{"id":"minecraft:yellow_wool","localizedName":"Yellow Wool","maxStackSize":64,"unlocalizedName":"block.minecraft.yellow_wool"},{"id":"minecraft:zoglin_spawn_egg","localizedName":"Zoglin Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.zoglin_spawn_egg"},{"id":"minecraft:zombie_head","localizedName":"Zombie Head","maxStackSize":64,"unlocalizedName":"block.minecraft.zombie_head"},{"id":"minecraft:zombie_horse_spawn_egg","localizedName":"Zombie Horse Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_horse_spawn_egg"},{"id":"minecraft:zombie_spawn_egg","localizedName":"Zombie Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_spawn_egg"},{"id":"minecraft:zombie_villager_spawn_egg","localizedName":"Zombie Villager Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.zombie_villager_spawn_egg"},{"id":"minecraft:zombified_piglin_spawn_egg","localizedName":"Zombified Piglin Spawn Egg","maxStackSize":64,"unlocalizedName":"item.minecraft.zombified_piglin_spawn_egg"}] From c4267b374628265f88b9a8ee29e40c7c7f156129 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sat, 23 Nov 2024 23:43:07 +0100 Subject: [PATCH 452/466] Send forget packet to avoid invisible chunk sections (#3005) --- .../impl/fawe/v1_21_3/PaperweightPlatformAdapter.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightPlatformAdapter.java index de2cf8acf..e7fb1b395 100644 --- a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightPlatformAdapter.java @@ -24,6 +24,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.IdMap; import net.minecraft.core.Registry; +import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkHolder; @@ -335,7 +336,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { if (chunkHolder == null) { return; } - ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ); LevelChunk levelChunk; if (PaperLib.isPaper()) { // getChunkAtIfLoadedImmediately is paper only @@ -353,6 +353,10 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } MinecraftServer.getServer().execute(() -> { try { + ChunkPos pos = levelChunk.getPos(); + // NOTE: the ClientboundForgetLevelChunkPacket packet is required on 1.21.3 + // as the client won't update empty -> non-empty sections properly otherwise + ClientboundForgetLevelChunkPacket forget = new ClientboundForgetLevelChunkPacket(pos); ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { packet = new ClientboundLevelChunkWithLightPacket( @@ -371,7 +375,10 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { null ); } - nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); + nearbyPlayers(nmsWorld, pos).forEach(p -> { + p.connection.send(forget); + p.connection.send(packet); + }); } finally { NMSAdapter.endChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder); } From 9d42b5db70691073e92540ca23c80d22425b072d Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sun, 24 Nov 2024 10:52:43 +0100 Subject: [PATCH 453/466] Move some classes to their expected location (#3004) --- buildSrc/src/main/kotlin/PlatformConfig.kt | 1 + worldedit-bukkit/build.gradle.kts | 1 + .../core/extension/factory/parser/mask/RichMaskParser.java | 2 +- .../src/main/java/com/sk89q/worldedit/EditSession.java | 2 +- .../core => sk89q/worldedit}/function/mask/MaskUnion.java | 6 +----- .../core => sk89q/worldedit}/function/mask/MaskUnion2D.java | 4 +--- 6 files changed, 6 insertions(+), 10 deletions(-) rename worldedit-core/src/main/java/com/{fastasyncworldedit/core => sk89q/worldedit}/function/mask/MaskUnion.java (91%) rename worldedit-core/src/main/java/com/{fastasyncworldedit/core => sk89q/worldedit}/function/mask/MaskUnion2D.java (86%) diff --git a/buildSrc/src/main/kotlin/PlatformConfig.kt b/buildSrc/src/main/kotlin/PlatformConfig.kt index 6a2c9d7ee..1b89a362e 100644 --- a/buildSrc/src/main/kotlin/PlatformConfig.kt +++ b/buildSrc/src/main/kotlin/PlatformConfig.kt @@ -134,6 +134,7 @@ fun Project.applyPlatformAndCoreConfiguration() { fun Project.applyShadowConfiguration() { tasks.withType().configureEach { + relocate("com.sk89q.jchronic", "com.sk89q.worldedit.jchronic") dependencies { include(project(":worldedit-libs:core")) include(project(":worldedit-libs:${project.name.replace("worldedit-", "")}")) diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index 8a9f43556..eadc70c8e 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -203,6 +203,7 @@ tasks.withType().configureEach { relocate("it.unimi.dsi.fastutil", "com.sk89q.worldedit.bukkit.fastutil") { include(dependency("it.unimi.dsi:fastutil")) } + relocate("net.royawesome.jlibnoise", "com.sk89q.worldedit.jlibnoise") relocate("org.incendo.serverlib", "com.fastasyncworldedit.serverlib") { include(dependency("dev.notmyfault.serverlib:ServerLib:2.3.6")) } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java index 1b6640ecd..4086d5d3d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java @@ -4,7 +4,7 @@ import com.fastasyncworldedit.core.command.SuggestInputParseException; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.extension.factory.parser.FaweParser; import com.fastasyncworldedit.core.function.mask.BlockMaskBuilder; -import com.fastasyncworldedit.core.function.mask.MaskUnion; +import com.sk89q.worldedit.function.mask.MaskUnion; import com.fastasyncworldedit.core.util.StringMan; import com.sk89q.minecraft.util.commands.CommandLocals; import com.sk89q.worldedit.WorldEdit; 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 7986ee366..b66b98897 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -38,7 +38,7 @@ import com.fastasyncworldedit.core.function.generator.GenBase; import com.fastasyncworldedit.core.function.generator.OreGen; import com.fastasyncworldedit.core.function.generator.SchemGen; import com.fastasyncworldedit.core.function.mask.BlockMaskBuilder; -import com.fastasyncworldedit.core.function.mask.MaskUnion; +import com.sk89q.worldedit.function.mask.MaskUnion; import com.fastasyncworldedit.core.function.mask.ResettableMask; import com.fastasyncworldedit.core.function.mask.SingleBlockTypeMask; import com.fastasyncworldedit.core.function.mask.WallMakeMask; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/MaskUnion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java similarity index 91% rename from worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/MaskUnion.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java index 381754a3c..e35ac319d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/MaskUnion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java @@ -1,9 +1,5 @@ -package com.fastasyncworldedit.core.function.mask; +package com.sk89q.worldedit.function.mask; -import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.function.mask.Mask2D; -import com.sk89q.worldedit.function.mask.MaskIntersection; -import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.math.BlockVector3; import javax.annotation.Nullable; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/MaskUnion2D.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion2D.java similarity index 86% rename from worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/MaskUnion2D.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion2D.java index 53edf2c45..a7995a9cf 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/MaskUnion2D.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion2D.java @@ -1,7 +1,5 @@ -package com.fastasyncworldedit.core.function.mask; +package com.sk89q.worldedit.function.mask; -import com.sk89q.worldedit.function.mask.Mask2D; -import com.sk89q.worldedit.function.mask.MaskIntersection2D; import com.sk89q.worldedit.math.BlockVector2; import java.util.Collection; From b4bcfd6189e966049a9f050387dcc3e042940de5 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 24 Nov 2024 18:27:47 +0100 Subject: [PATCH 454/466] Use Modrinth ID Signed-off-by: Alexander Brandes --- worldedit-bukkit/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index eadc70c8e..6a6ba7dc2 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -245,7 +245,7 @@ publishMods { val common = modrinthOptions { accessToken.set(System.getenv("MODRINTH_TOKEN")) - projectId.set("fastasyncworldedit") + projectId.set("z4HZZnLr") projectDescription.set(rootProject.file("README.md").readText()) } From 418d098eaacbb500974ca46d2681fd0f369d619b Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 24 Nov 2024 18:34:11 +0100 Subject: [PATCH 455/466] Fix 'Fawe#getClipboardExecutor()' deprecation javadocs Signed-off-by: Alexander Brandes --- .../src/main/java/com/fastasyncworldedit/core/Fawe.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java index f20482f23..028f312ee 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java @@ -466,7 +466,7 @@ public class Fawe { * @return Executor used for clipboard IO if clipboard on disk is enabled or null * @since 2.6.2 * @deprecated Use any of {@link Fawe#submitUUIDKeyQueuedTask(UUID, Runnable)}, - * {@link Fawe#submitUUIDKeyQueuedTask(UUID, Runnable, Object), {@link Fawe#submitUUIDKeyQueuedTask(UUID, Callable)} + * {@link Fawe#submitUUIDKeyQueuedTask(UUID, Runnable, Object)}, {@link Fawe#submitUUIDKeyQueuedTask(UUID, Callable)} * to ensure if a thread is already a UUID-queued thread, the task is immediately run */ @Deprecated(forRemoval = true, since = "2.12.1") From 79dab6e776c6005b24dcb18bfaaa9d0caa8f70cb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 24 Nov 2024 17:34:26 +0000 Subject: [PATCH 456/466] Update plotsquared to v7.4.0 (#3009) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c3112c66a..a8a195662 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" towny = "0.100.4.13" -plotsquared = "7.3.12" +plotsquared = "7.4.0" # Third party bstats = "3.1.0" From 57cfa42e64fceb3500acbd21f428a754f8387b94 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 24 Nov 2024 17:37:39 +0000 Subject: [PATCH 457/466] Update dependency gradle to v8.11.1 (#3007) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 94113f200..e2847c820 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 3bd5b956c590a3af09d291b9472d52486c750b86 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 24 Nov 2024 18:46:57 +0100 Subject: [PATCH 458/466] Refactor 'Fawe' javadoc for better readibility Signed-off-by: Alexander Brandes --- .../com/fastasyncworldedit/core/Fawe.java | 50 ++++++++----------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java index 028f312ee..9045d0e0e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java @@ -45,41 +45,35 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** - * [ WorldEdit action] - * | - * \|/ + * [ WorldEdit action ] + *
    * [ EditSession ] - The change is processed (area restrictions, change limit, block type) - * | - * \|/ - * [Block change] - A block change from some location - * | - * \|/ + *
    + * [ Block change ] - A block change from some location + *
    * [ Set Queue ] - The SetQueue manages the implementation specific queue - * | - * \|/ + *
    * [ Fawe Queue] - A queue of chunks - check if the queue has the chunk for a change - * | - * \|/ + *
    * [ Fawe Chunk Implementation ] - Otherwise create a new FaweChunk object which is a wrapper around the Chunk object - * | - * \|/ + *
    * [ Execution ] - When done, the queue then sets the blocks for the chunk, performs lighting updates and sends the chunk packet to the clients *

    * Why it's faster: - * - The chunk is modified directly rather than through the API - * \ Removes some overhead, and means some processing can be done async - * - Lighting updates are performed on the chunk level rather than for every block - * \ e.g., A blob of stone: only the visible blocks need to have the lighting calculated - * - Block changes are sent with a chunk packet - * \ A chunk packet is generally quicker to create and smaller for large world edits - * - No physics updates - * \ Physics updates are slow, and are usually performed on each block - * - Block data shortcuts - * \ Some known blocks don't need to have the data set or accessed (e.g., air is never going to have data) - * - Remove redundant extents - * \ Up to 11 layers of extents can be removed - * - History bypassing - * \ FastMode bypasses history and means blocks in the world don't need to be checked and recorded + *
    The chunk is modified directly rather than through the API + * - Removes some overhead, and means some processing can be done async + *
    Lighting updates are performed on the chunk level rather than for every block + * - e.g., A blob of stone: only the visible blocks need to have the lighting calculated + *
    Block changes are sent with a chunk packet + * - A chunk packet is generally quicker to create and smaller for large world edits + *
    No physics updates + * - Physics updates are slow, and are usually performed on each block + *
    Block data shortcuts + * - Some known blocks don't need to have the data set or accessed (e.g., air is never going to have data) + *
    Remove redundant extents + * - Up to 11 layers of extents can be removed + *
    History bypassing + * - FastMode bypasses history and means blocks in the world don't need to be checked and recorded */ public class Fawe { From 0acbeb2eecbfcc6ea8d1e850ec7ff940b0ff4074 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 24 Nov 2024 17:55:11 +0000 Subject: [PATCH 459/466] Update dependency paperweight-userdev (#3008) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts | 2 +- worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts index 8393bd1dc..4164c6262 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.1-R0.1-20241031.174552-126") + the().paperDevBundle("1.21.1-R0.1-20241121.101634-127") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts index b647fa0a8..6beca9414 100644 --- a/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.3-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.3-R0.1-20241119.112919-49") + the().paperDevBundle("1.21.3-R0.1-20241124.172806-62") compileOnly(libs.paperlib) } From 0b571b5e3a53e374ef1a9e07da4b32cf96a312d1 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 24 Nov 2024 19:44:32 +0100 Subject: [PATCH 460/466] Release 2.12.2 Signed-off-by: Alexander Brandes --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 02cdc2f03..40a16a968 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s-%s", rootVersion, buildNumber) +version = String.format("%s", rootVersion) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From c5f66d30d2771798baee16190776dce6e533f262 Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Sun, 24 Nov 2024 19:53:28 +0100 Subject: [PATCH 461/466] Back to snapshot for development Signed-off-by: Alexander Brandes --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 40a16a968..5b5f3a42b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.12.2") +var rootVersion by extra("2.12.3") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -52,7 +52,7 @@ ext { } } -version = String.format("%s", rootVersion) +version = String.format("%s-%s", rootVersion, buildNumber) if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") From 619867e867ddc59e0db5415892851344c3d769db Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 00:52:16 +0000 Subject: [PATCH 462/466] Update dependency paperweight-userdev to v1.21.3-R0.1-20241124.214153-64 (#3010) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts index 6beca9414..fb3f7fcd2 100644 --- a/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21_3/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.3-R0.1-SNAPSHOT/ - the().paperDevBundle("1.21.3-R0.1-20241124.172806-62") + the().paperDevBundle("1.21.3-R0.1-20241124.214153-64") compileOnly(libs.paperlib) } From a2a5545ecd6d5c36e001c92e3f35b86e64450955 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 19:37:43 +0000 Subject: [PATCH 463/466] Update dependency me.modmuss50.mod-publish-plugin to v0.8.1 (#3011) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a8a195662..4b2bea419 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -51,7 +51,7 @@ mockito = "5.14.2" # Gradle plugins pluginyml = "0.6.0" -mod-publish-plugin = "0.8.0" +mod-publish-plugin = "0.8.1" [libraries] # Minecraft expectations From 0b78d0a40dcf9a65df963c83d690649f963c8c7e Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Thu, 28 Nov 2024 00:21:57 +0100 Subject: [PATCH 464/466] Update FaWe --- steamwarci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/steamwarci.yml b/steamwarci.yml index ff7ddde8c..ca4f91205 100644 --- a/steamwarci.yml +++ b/steamwarci.yml @@ -3,7 +3,7 @@ build: - "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew --stop" artifacts: - "/binarys/FastAsyncWorldEdit-1.18.jar": "worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-2.7.1-SNAPSHOT.jar" + "/binarys/FastAsyncWorldEdit-1.21.jar": "worldedit-bukkit/build/libs/FastAsyncWorldEdit-Paper-2.12.3-SNAPSHOT.jar" release: - - "mvn deploy:deploy-file -DgroupId=de.steamwar -DartifactId=fastasyncworldedit -Dversion=1.18 -Dpackaging=jar -Dfile=/binarys/FastAsyncWorldEdit-1.18.jar -Durl=file:///var/www/html/maven/" + - "mvn deploy:deploy-file -DgroupId=de.steamwar -DartifactId=fastasyncworldedit -Dversion=1.21 -Dpackaging=jar -Dfile=/binarys/FastAsyncWorldEdit-1.21.jar -Durl=file:///var/www/html/maven/" From c7acc3ffce03d3701207b28188d7fd271133fd99 Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Thu, 28 Nov 2024 00:23:26 +0100 Subject: [PATCH 465/466] Fix CI --- steamwarci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/steamwarci.yml b/steamwarci.yml index ca4f91205..612416b6b 100644 --- a/steamwarci.yml +++ b/steamwarci.yml @@ -1,6 +1,6 @@ build: - - "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew build" - - "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew --stop" + - "JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 ./gradlew build" + - "JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 ./gradlew --stop" artifacts: "/binarys/FastAsyncWorldEdit-1.21.jar": "worldedit-bukkit/build/libs/FastAsyncWorldEdit-Paper-2.12.3-SNAPSHOT.jar" From d99b6a7e95ba5c73cb31e6f1577bf2af959a4c2e Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Thu, 28 Nov 2024 22:25:26 +0100 Subject: [PATCH 466/466] Delete Unused Adapters --- .../adapters/adapter-1_19/build.gradle.kts | 16 - .../ext/fawe/v1_19_R1/PaperweightAdapter.java | 1009 ------ .../v1_19_R1/PaperweightDataConverters.java | 2955 ----------------- .../fawe/v1_19_R1/PaperweightFakePlayer.java | 99 - .../PaperweightWorldNativeAccess.java | 210 -- .../v1_19_R1/PaperweightBlockMaterial.java | 189 -- .../fawe/v1_19_R1/PaperweightFaweAdapter.java | 701 ---- .../PaperweightFaweWorldNativeAccess.java | 286 -- .../fawe/v1_19_R1/PaperweightGetBlocks.java | 1164 ------- .../v1_19_R1/PaperweightGetBlocks_Copy.java | 248 -- .../v1_19_R1/PaperweightMapChunkUtil.java | 35 - .../v1_19_R1/PaperweightPlatformAdapter.java | 703 ---- .../v1_19_R1/PaperweightPostProcessor.java | 175 - .../PaperweightStarlightRelighter.java | 205 -- .../PaperweightStarlightRelighterFactory.java | 28 - .../nbt/PaperweightLazyCompoundTag.java | 161 - .../fawe/v1_19_R1/regen/PaperweightRegen.java | 564 ---- .../adapters/adapter-1_19_3/build.gradle.kts | 17 - .../ext/fawe/v1_19_R2/PaperweightAdapter.java | 1029 ------ .../v1_19_R2/PaperweightDataConverters.java | 2800 ---------------- .../fawe/v1_19_R2/PaperweightFakePlayer.java | 93 - .../PaperweightWorldNativeAccess.java | 180 - .../v1_19_R2/PaperweightBlockMaterial.java | 189 -- .../fawe/v1_19_R2/PaperweightFaweAdapter.java | 706 ---- .../PaperweightFaweWorldNativeAccess.java | 286 -- .../fawe/v1_19_R2/PaperweightGetBlocks.java | 1170 ------- .../v1_19_R2/PaperweightGetBlocks_Copy.java | 248 -- .../v1_19_R2/PaperweightMapChunkUtil.java | 34 - .../v1_19_R2/PaperweightPlatformAdapter.java | 700 ---- .../v1_19_R2/PaperweightPostProcessor.java | 175 - .../PaperweightStarlightRelighter.java | 205 -- .../PaperweightStarlightRelighterFactory.java | 28 - .../nbt/PaperweightLazyCompoundTag.java | 161 - .../fawe/v1_19_R2/regen/PaperweightRegen.java | 594 ---- 34 files changed, 17363 deletions(-) delete mode 100644 worldedit-bukkit/adapters/adapter-1_19/build.gradle.kts delete mode 100644 worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R1/PaperweightAdapter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R1/PaperweightDataConverters.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R1/PaperweightFakePlayer.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R1/PaperweightWorldNativeAccess.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightBlockMaterial.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightFaweAdapter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightFaweWorldNativeAccess.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightGetBlocks.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightGetBlocks_Copy.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightMapChunkUtil.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightPlatformAdapter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightPostProcessor.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightStarlightRelighter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightStarlightRelighterFactory.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/nbt/PaperweightLazyCompoundTag.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/regen/PaperweightRegen.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_3/build.gradle.kts delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R2/PaperweightAdapter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R2/PaperweightDataConverters.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R2/PaperweightFakePlayer.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R2/PaperweightWorldNativeAccess.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightBlockMaterial.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightFaweAdapter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightFaweWorldNativeAccess.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightGetBlocks.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightGetBlocks_Copy.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightMapChunkUtil.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightPlatformAdapter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightPostProcessor.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightStarlightRelighter.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightStarlightRelighterFactory.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/nbt/PaperweightLazyCompoundTag.java delete mode 100644 worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/regen/PaperweightRegen.java diff --git a/worldedit-bukkit/adapters/adapter-1_19/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_19/build.gradle.kts deleted file mode 100644 index a0ca70d2b..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19/build.gradle.kts +++ /dev/null @@ -1,16 +0,0 @@ -import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension - -plugins { - java -} - -applyPaperweightAdapterConfiguration() - -repositories { - gradlePluginPortal() -} - -dependencies { - the().paperDevBundle("1.19.2-R0.1-20221206.184705-189") - compileOnly(libs.paperlib) -} diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R1/PaperweightAdapter.java deleted file mode 100644 index 1e8ed0c56..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R1/PaperweightAdapter.java +++ /dev/null @@ -1,1009 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R1; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.google.common.util.concurrent.Futures; -import com.mojang.datafixers.util.Either; -import com.mojang.serialization.Lifecycle; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.blocks.BaseItem; -import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1.PaperweightFaweAdapter; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.extension.platform.Watchdog; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.Constants; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; -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.util.SideEffect; -import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; -import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.ByteBinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; -import com.sk89q.worldedit.util.nbt.EndBinaryTag; -import com.sk89q.worldedit.util.nbt.FloatBinaryTag; -import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; -import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.LongBinaryTag; -import com.sk89q.worldedit.util.nbt.ShortBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; -import com.sk89q.worldedit.world.DataFixer; -import com.sk89q.worldedit.world.RegenOptions; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.BiomeTypes; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.item.ItemType; -import net.minecraft.Util; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Registry; -import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; -import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.progress.ChunkProgressListener; -import net.minecraft.util.StringRepresentable; -import net.minecraft.util.thread.BlockableEventLoop; -import net.minecraft.world.Clearable; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelSettings; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.StructureBlockEntity; -import net.minecraft.world.level.block.state.StateDefinition; -import net.minecraft.world.level.block.state.properties.DirectionProperty; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.WorldGenSettings; -import net.minecraft.world.level.storage.LevelStorageSource; -import net.minecraft.world.level.storage.PrimaryLevelData; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World.Environment; -import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_19_R1.CraftServer; -import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_19_R1.util.CraftMagicNumbers; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; -import org.bukkit.generator.ChunkGenerator; -import org.spigotmc.SpigotConfig; -import org.spigotmc.WatchdogThread; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.OptionalInt; -import java.util.OptionalLong; -import java.util.Set; -import java.util.TreeMap; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ForkJoinPool; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -public final class PaperweightAdapter implements BukkitImplAdapter { - - private final Logger LOGGER = Logger.getLogger(getClass().getCanonicalName()); - - private final Field worldsField; - private final Method getChunkFutureMainThreadMethod; - private final Field mainThreadProcessorField; - private final Watchdog watchdog; - - // ------------------------------------------------------------------------ - // Code that may break between versions of Minecraft - // ------------------------------------------------------------------------ - - public PaperweightAdapter() throws NoSuchFieldException, NoSuchMethodException { - // A simple test - CraftServer.class.cast(Bukkit.getServer()); - - int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); - if (dataVersion != 3105 && dataVersion != 3117 && dataVersion != 3120) { - throw new UnsupportedClassVersionError("Not 1.19, 1.19.1 or 1.19.2!"); - } - - worldsField = CraftServer.class.getDeclaredField("worlds"); - worldsField.setAccessible(true); - - getChunkFutureMainThreadMethod = ServerChunkCache.class.getDeclaredMethod( - Refraction.pickName("getChunkFutureMainThread", "c"), - int.class, int.class, ChunkStatus.class, boolean.class - ); - getChunkFutureMainThreadMethod.setAccessible(true); - - mainThreadProcessorField = ServerChunkCache.class.getDeclaredField( - Refraction.pickName("mainThreadProcessor", "g") - ); - mainThreadProcessorField.setAccessible(true); - - new PaperweightDataConverters(CraftMagicNumbers.INSTANCE.getDataVersion(), this).buildUnoptimized(); - - Watchdog watchdog; - try { - Class.forName("org.spigotmc.WatchdogThread"); - watchdog = new SpigotWatchdog(); - } catch (ClassNotFoundException | NoSuchFieldException e) { - try { - watchdog = new MojangWatchdog(((CraftServer) Bukkit.getServer()).getServer()); - } catch (NoSuchFieldException ex) { - watchdog = null; - } - } - this.watchdog = watchdog; - - try { - Class.forName("org.spigotmc.SpigotConfig"); - SpigotConfig.config.set("world-settings.faweregentempworld.verbose", false); - } catch (ClassNotFoundException ignored) { - } - } - - @Override - public DataFixer getDataFixer() { - return PaperweightDataConverters.INSTANCE; - } - - /** - * Read the given NBT data into the given tile entity. - * - * @param tileEntity the tile entity - * @param tag the tag - */ - static void readTagIntoTileEntity(net.minecraft.nbt.CompoundTag tag, BlockEntity tileEntity) { - tileEntity.load(tag); - tileEntity.setChanged(); - } - - /** - * Get the ID string of the given entity. - * - * @param entity the entity - * @return the entity ID - */ - private static String getEntityId(Entity entity) { - return EntityType.getKey(entity.getType()).toString(); - } - - /** - * Create an entity using the given entity ID. - * - * @param id the entity ID - * @param world the world - * @return an entity or null - */ - @Nullable - private static Entity createEntityFromId(String id, net.minecraft.world.level.Level world) { - return EntityType.byString(id).map(t -> t.create(world)).orElse(null); - } - - /** - * Write the given NBT data into the given entity. - * - * @param entity the entity - * @param tag the tag - */ - private static void readTagIntoEntity(net.minecraft.nbt.CompoundTag tag, Entity entity) { - entity.load(tag); - } - - /** - * Write the entity's NBT data to the given tag. - * - * @param entity the entity - * @param tag the tag - */ - private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag tag) { - entity.save(tag); - } - - private static Block getBlockFromType(BlockType blockType) { - return Registry.BLOCK.get(ResourceLocation.tryParse(blockType.getId())); - } - - private static Item getItemFromType(ItemType itemType) { - return Registry.ITEM.get(ResourceLocation.tryParse(itemType.getId())); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockData data) { - net.minecraft.world.level.block.state.BlockState state = ((CraftBlockData) data).getState(); - int combinedId = Block.getId(state); - return combinedId == 0 && state.getBlock() != Blocks.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockState state) { - Block mcBlock = getBlockFromType(state.getBlockType()); - net.minecraft.world.level.block.state.BlockState newState = mcBlock.defaultBlockState(); - Map, Object> states = state.getStates(); - newState = applyProperties(mcBlock.getStateDefinition(), newState, states); - final int combinedId = Block.getId(newState); - return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); - } - - @Override - public BlockState getBlock(Location location) { - checkNotNull(location); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - final CraftBlockData blockData = chunk.getBlockState(blockPos).createCraftBlockData(); - BlockState state = BukkitAdapter.adapt(blockData); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - - return state; - } - - @Override - public BaseBlock getFullBlock(Location location) { - BlockState state = getBlock(location); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - - // Read the NBT data - BlockEntity te = chunk.getBlockEntity(blockPos); - if (te != null) { - net.minecraft.nbt.CompoundTag tag = te.saveWithId(); - //FAWE start - BinaryTag - return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); - //FAWE end - } - - return state.toBaseBlock(); - } - - @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightWorldNativeAccess( - this, - new WeakReference<>(((CraftWorld) world).getHandle()) - ); - } - - private static net.minecraft.core.Direction adapt(Direction face) { - switch (face) { - case NORTH: - return net.minecraft.core.Direction.NORTH; - case SOUTH: - return net.minecraft.core.Direction.SOUTH; - case WEST: - return net.minecraft.core.Direction.WEST; - case EAST: - return net.minecraft.core.Direction.EAST; - case DOWN: - return net.minecraft.core.Direction.DOWN; - case UP: - default: - return net.minecraft.core.Direction.UP; - } - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - private net.minecraft.world.level.block.state.BlockState applyProperties( - StateDefinition stateContainer, - net.minecraft.world.level.block.state.BlockState newState, - Map, Object> states - ) { - for (Map.Entry, Object> state : states.entrySet()) { - net.minecraft.world.level.block.state.properties.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.world.level.block.state.properties.EnumProperty) { - String enumName = (String) value; - value = ((net.minecraft.world.level.block.state.properties.EnumProperty) property) - .getValue(enumName).orElseThrow(() -> - new IllegalStateException( - "Enum property " + property.getName() + " does not contain " + enumName - ) - ); - } - - newState = newState.setValue( - (net.minecraft.world.level.block.state.properties.Property) property, - (Comparable) value - ); - } - return newState; - } - - @Override - public BaseEntity getEntity(org.bukkit.entity.Entity entity) { - checkNotNull(entity); - - CraftEntity craftEntity = ((CraftEntity) entity); - Entity mcEntity = craftEntity.getHandle(); - - String id = getEntityId(mcEntity); - - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - readEntityIntoTag(mcEntity, tag); - //FAWE start - BinaryTag - return new BaseEntity( - com.sk89q.worldedit.world.entity.EntityTypes.get(id), - LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag)) - ); - //FAWE end - } - - @Nullable - @Override - public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state) { - checkNotNull(location); - checkNotNull(state); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - ServerLevel worldServer = craftWorld.getHandle(); - - Entity createdEntity = createEntityFromId(state.getType().getId(), craftWorld.getHandle()); - - if (createdEntity != null) { - CompoundBinaryTag nativeTag = state.getNbt(); - if (nativeTag != null) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(nativeTag); - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - readTagIntoEntity(tag, createdEntity); - } - - createdEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - - worldServer.addFreshEntity(createdEntity, SpawnReason.CUSTOM); - return createdEntity.getBukkitEntity(); - } else { - return null; - } - } - - @Override - public Component getRichBlockName(BlockType blockType) { - return TranslatableComponent.of(getBlockFromType(blockType).getDescriptionId()); - } - - @Override - public Component getRichItemName(ItemType itemType) { - return TranslatableComponent.of(getItemFromType(itemType).getDescriptionId()); - } - - @Override - public Component getRichItemName(BaseItemStack itemStack) { - return TranslatableComponent.of(CraftItemStack.asNMSCopy(BukkitAdapter.adapt(itemStack)).getDescriptionId()); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private static final LoadingCache> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { - @Override - public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else if (state instanceof DirectionProperty) { - return new DirectionalProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - return new EnumProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else { - throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); - } - } - }); - - @SuppressWarnings({ "rawtypes" }) - @Override - public Map> getProperties(BlockType blockType) { - Map> properties = new TreeMap<>(); - Block block = getBlockFromType(blockType); - StateDefinition blockStateList = - block.getStateDefinition(); - for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { - Property property = PROPERTY_CACHE.getUnchecked(state); - properties.put(property.getName(), property); - } - return properties; - } - - @Override - public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { - ((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create( - new StructureBlockEntity( - new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()), - Blocks.STRUCTURE_BLOCK.defaultBlockState() - ), - __ -> (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) - )); - } - - @Override - public void sendFakeOP(Player player) { - ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( - ((CraftPlayer) player).getHandle(), (byte) 28 - )); - } - - @Override - public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { - ItemStack stack = new ItemStack(Registry.ITEM.get(ResourceLocation.tryParse(item.getType().getId())), item.getAmount()); - stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData()))); - return CraftItemStack.asCraftMirror(stack); - } - - @Override - public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { - final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); - final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); - weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); - return weStack; - } - - private final LoadingCache fakePlayers - = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); - - @Override - public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) { - CraftWorld craftWorld = (CraftWorld) world; - ServerLevel worldServer = craftWorld.getHandle(); - ItemStack stack = CraftItemStack.asNMSCopy(BukkitAdapter.adapt(item instanceof BaseItemStack - ? ((BaseItemStack) item) : new BaseItemStack(item.getType(), item.getNbtData(), 1))); - stack.setTag((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData())); - - PaperweightFakePlayer fakePlayer; - try { - fakePlayer = fakePlayers.get(worldServer); - } catch (ExecutionException ignored) { - return false; - } - fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); - fakePlayer.absMoveTo(position.getBlockX(), position.getBlockY(), position.getBlockZ(), - (float) face.toVector().toYaw(), (float) face.toVector().toPitch() - ); - - final BlockPos blockPos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos); - final net.minecraft.core.Direction enumFacing = adapt(face); - BlockHitResult rayTrace = new BlockHitResult(blockVec, enumFacing, blockPos, false); - UseOnContext context = new UseOnContext(fakePlayer, InteractionHand.MAIN_HAND, rayTrace); - InteractionResult result = stack.useOn(context, InteractionHand.MAIN_HAND); - if (result != InteractionResult.SUCCESS) { - if (worldServer - .getBlockState(blockPos) - .use(worldServer, fakePlayer, InteractionHand.MAIN_HAND, rayTrace) - .consumesAction()) { - result = InteractionResult.SUCCESS; - } else { - result = stack.getItem().use(worldServer, fakePlayer, InteractionHand.MAIN_HAND).getResult(); - } - } - - return result == InteractionResult.SUCCESS; - } - - @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 position, BlockState blockState) { - int internalId = BlockStateIdAccess.getBlockStateId(blockState); - net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId); - return blockData.canSurvive( - ((CraftWorld) world).getHandle(), - new BlockPos(position.getX(), position.getY(), position.getZ()) - ); - } - - @Override - public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) { - try { - doRegen(bukkitWorld, region, extent, options); - } catch (Exception e) { - throw new IllegalStateException("Regen failed.", e); - } - - return true; - } - - private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { - Environment env = bukkitWorld.getEnvironment(); - ChunkGenerator gen = bukkitWorld.getGenerator(); - - Path tempDir = Files.createTempDirectory("FastAsyncWorldEditWorldGen"); - LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir); - ResourceKey worldDimKey = getWorldDimKey(env); - try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { - ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); - PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() - .getWorldData().overworldData(); - WorldGenSettings originalOpts = levelProperties.worldGenSettings(); - - long seed = options.getSeed().orElse(originalWorld.getSeed()); - WorldGenSettings newOpts = options.getSeed().isPresent() - ? originalOpts.withSeed(levelProperties.isHardcore(), OptionalLong.of(seed)) - : originalOpts; - - LevelSettings newWorldSettings = new LevelSettings( - "faweregentempworld", - levelProperties.settings.gameType(), - levelProperties.settings.hardcore(), - levelProperties.settings.difficulty(), - levelProperties.settings.allowCommands(), - levelProperties.settings.gameRules(), - levelProperties.settings.getDataPackConfig() - ); - PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, Lifecycle.stable()); - - ServerLevel freshWorld = new ServerLevel( - originalWorld.getServer(), - originalWorld.getServer().executor, - session, newWorldData, - originalWorld.dimension(), - new LevelStem( - originalWorld.dimensionTypeRegistration(), - newOpts.dimensions().get(worldDimKey).generator() - ), - new NoOpWorldLoadListener(), - originalWorld.isDebug(), - seed, - ImmutableList.of(), - false, - env, - gen, - bukkitWorld.getBiomeProvider() - ); - try { - regenForWorld(region, extent, freshWorld, options); - } finally { - freshWorld.getChunkSource().close(false); - } - } finally { - try { - @SuppressWarnings("unchecked") - Map map = (Map) worldsField.get(Bukkit.getServer()); - map.remove("faweregentempworld"); - } catch (IllegalAccessException ignored) { - } - SafeFiles.tryHardToDeleteDir(tempDir); - } - } - - private BiomeType adapt(ServerLevel serverWorld, Biome origBiome) { - ResourceLocation key = serverWorld.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY).getKey(origBiome); - if (key == null) { - return null; - } - return BiomeTypes.get(key.toString()); - } - - @SuppressWarnings("unchecked") - private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld, RegenOptions options) throws - WorldEditException { - List> chunkLoadings = submitChunkLoadTasks(region, serverWorld); - BlockableEventLoop executor; - try { - executor = (BlockableEventLoop) mainThreadProcessorField.get(serverWorld.getChunkSource()); - } catch (IllegalAccessException e) { - throw new IllegalStateException("Couldn't get executor for chunk loading.", e); - } - executor.managedBlock(() -> { - // bail out early if a future fails - if (chunkLoadings.stream().anyMatch(ftr -> - ftr.isDone() && Futures.getUnchecked(ftr) == null - )) { - return false; - } - return chunkLoadings.stream().allMatch(CompletableFuture::isDone); - }); - Map chunks = new HashMap<>(); - for (CompletableFuture future : chunkLoadings) { - @Nullable - ChunkAccess chunk = future.getNow(null); - checkState(chunk != null, "Failed to generate a chunk, regen failed."); - chunks.put(chunk.getPos(), chunk); - } - - for (BlockVector3 vec : region) { - BlockPos pos = new BlockPos(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()); - ChunkAccess chunk = chunks.get(new ChunkPos(pos)); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(pos); - BlockStateHolder state = ((PaperweightFaweAdapter) WorldEditPlugin - .getInstance() - .getBukkitImplAdapter()).adapt(blockData); - Objects.requireNonNull(state); - BlockEntity blockEntity = chunk.getBlockEntity(pos); - if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); - //FAWE start - BinaryTag - state = state.toBaseBlock(((CompoundBinaryTag) toNativeBinary(tag))); - //FAWE end - } - extent.setBlock(vec, state.toBaseBlock()); - if (options.shouldRegenBiomes()) { - Biome origBiome = chunk.getNoiseBiome(vec.getX(), vec.getY(), vec.getZ()).value(); - BiomeType adaptedBiome = adapt(serverWorld, origBiome); - if (adaptedBiome != null) { - extent.setBiome(vec, adaptedBiome); - } - } - } - } - - @SuppressWarnings("unchecked") - private List> submitChunkLoadTasks(Region region, ServerLevel serverWorld) { - ServerChunkCache chunkManager = serverWorld.getChunkSource(); - List> chunkLoadings = new ArrayList<>(); - // Pre-gen all the chunks - for (BlockVector2 chunk : region.getChunks()) { - try { - chunkLoadings.add( - ((CompletableFuture>) - getChunkFutureMainThreadMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) - .thenApply(either -> either.left().orElse(null)) - ); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalStateException("Couldn't load chunk for regen.", e); - } - } - return chunkLoadings; - } - - private ResourceKey getWorldDimKey(Environment env) { - switch (env) { - case NETHER: - return LevelStem.NETHER; - case THE_END: - return LevelStem.END; - case NORMAL: - default: - return LevelStem.OVERWORLD; - } - } - - private static final Set SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( - SideEffect.NEIGHBORS, - SideEffect.LIGHTING, - SideEffect.VALIDATION, - SideEffect.ENTITY_AI, - SideEffect.EVENTS, - SideEffect.UPDATE - ); - - @Override - public Set getSupportedSideEffects() { - return SUPPORTED_SIDE_EFFECTS; - } - - @Override - public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) { - ServerLevel originalWorld = ((CraftWorld) world).getHandle(); - - BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); - if (entity instanceof Clearable) { - ((Clearable) entity).clearContent(); - return true; - } - return false; - } - - // ------------------------------------------------------------------------ - // Code that is less likely to break - // ------------------------------------------------------------------------ - - /** - * Converts from a non-native NMS NBT structure to a native WorldEdit NBT - * structure. - * - * @param foreign non-native NMS NBT structure - * @return native WorldEdit NBT structure - */ - //FAWE start - BinaryTag - @Override - public BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { - if (foreign == null) { - return null; - } - if (foreign instanceof net.minecraft.nbt.CompoundTag) { - Map values = new HashMap<>(); - Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); - - for (String str : foreignKeys) { - net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); - values.put(str, toNativeBinary(base)); - } - return CompoundBinaryTag.from(values); - } else if (foreign instanceof net.minecraft.nbt.ByteTag) { - return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); - } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { - return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); - } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { - return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); - } else if (foreign instanceof net.minecraft.nbt.FloatTag) { - return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); - } else if (foreign instanceof net.minecraft.nbt.IntTag) { - return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); - } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { - return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); - } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { - return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); - } else if (foreign instanceof net.minecraft.nbt.ListTag) { - try { - return toNativeList((net.minecraft.nbt.ListTag) foreign); - } catch (Throwable e) { - LOGGER.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); - return ListBinaryTag.empty(); - } - } else if (foreign instanceof net.minecraft.nbt.LongTag) { - return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); - } else if (foreign instanceof net.minecraft.nbt.ShortTag) { - return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); - } else if (foreign instanceof net.minecraft.nbt.StringTag) { - return StringBinaryTag.of(foreign.getAsString()); - } else if (foreign instanceof net.minecraft.nbt.EndTag) { - return EndBinaryTag.get(); - } else { - throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); - } - } - - /** - * Convert a foreign NBT list tag into a native WorldEdit one. - * - * @param foreign the foreign tag - * @return the converted tag - * @throws SecurityException on error - * @throws IllegalArgumentException on error - */ - private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { - ListBinaryTag.Builder values = ListBinaryTag.builder(); - - for (net.minecraft.nbt.Tag tag : foreign) { - values.add(toNativeBinary(tag)); - } - - return values.build(); - } - - /** - * Converts a WorldEdit-native NBT structure to a NMS structure. - * - * @param foreign structure to convert - * @return non-native structure - */ - @Override - public net.minecraft.nbt.Tag fromNativeBinary(BinaryTag foreign) { - if (foreign == null) { - return null; - } - if (foreign instanceof CompoundBinaryTag) { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - for (String key : ((CompoundBinaryTag) foreign).keySet()) { - tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); - } - return tag; - } else if (foreign instanceof ByteBinaryTag) { - return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); - } else if (foreign instanceof ByteArrayBinaryTag) { - return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); - } else if (foreign instanceof DoubleBinaryTag) { - return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); - } else if (foreign instanceof FloatBinaryTag) { - return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); - } else if (foreign instanceof IntBinaryTag) { - return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); - } else if (foreign instanceof IntArrayBinaryTag) { - return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); - } else if (foreign instanceof LongArrayBinaryTag) { - return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); - } else if (foreign instanceof ListBinaryTag) { - net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); - ListBinaryTag foreignList = (ListBinaryTag) foreign; - for (BinaryTag t : foreignList) { - tag.add(fromNativeBinary(t)); - } - return tag; - } else if (foreign instanceof LongBinaryTag) { - return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); - } else if (foreign instanceof ShortBinaryTag) { - return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); - } else if (foreign instanceof StringBinaryTag) { - return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); - } else if (foreign instanceof EndBinaryTag) { - return net.minecraft.nbt.EndTag.INSTANCE; - } else { - throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); - } - } - //FAWE end - - @Override - public boolean supportsWatchdog() { - return watchdog != null; - } - - @Override - public void tickWatchdog() { - watchdog.tick(); - } - - private class SpigotWatchdog implements Watchdog { - - private final Field instanceField; - private final Field lastTickField; - - SpigotWatchdog() throws NoSuchFieldException { - Field instanceField = WatchdogThread.class.getDeclaredField("instance"); - instanceField.setAccessible(true); - this.instanceField = instanceField; - - Field lastTickField = WatchdogThread.class.getDeclaredField("lastTick"); - lastTickField.setAccessible(true); - this.lastTickField = lastTickField; - } - - @Override - public void tick() { - try { - WatchdogThread instance = (WatchdogThread) this.instanceField.get(null); - if ((long) lastTickField.get(instance) != 0) { - WatchdogThread.tick(); - } - } catch (IllegalAccessException e) { - LOGGER.log(Level.WARNING, "Failed to tick watchdog", e); - } - } - - } - - private static class MojangWatchdog implements Watchdog { - - private final DedicatedServer server; - private final Field tickField; - - MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { - this.server = server; - Field tickField = MinecraftServer.class.getDeclaredField( - Refraction.pickName("nextTickTime", "ag") - ); - if (tickField.getType() != long.class) { - throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); - } - tickField.setAccessible(true); - this.tickField = tickField; - } - - @Override - public void tick() { - try { - tickField.set(server, Util.getMillis()); - } catch (IllegalAccessException ignored) { - } - } - - } - - private static class NoOpWorldLoadListener implements ChunkProgressListener { - - @Override - public void updateSpawnPos(ChunkPos spawnPos) { - } - - @Override - public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) { - } - - @Override - public void start() { - } - - @Override - public void stop() { - } - - @Override - public void setChunkRadius(int radius) { - } - - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R1/PaperweightDataConverters.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R1/PaperweightDataConverters.java deleted file mode 100644 index c9d8928bb..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R1/PaperweightDataConverters.java +++ /dev/null @@ -1,2955 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R1; - -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.schemas.Schema; -import com.mojang.serialization.Dynamic; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import net.minecraft.core.Direction; -import net.minecraft.nbt.NbtOps; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.GsonHelper; -import net.minecraft.util.StringUtil; -import net.minecraft.util.datafix.DataFixers; -import net.minecraft.util.datafix.fixes.References; -import net.minecraft.world.item.DyeColor; -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({"rawtypes", "unchecked"}) -class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { - - //FAWE start - BinaryTag - @SuppressWarnings("unchecked") - @Override - public T fixUp(FixType type, T original, int srcVer) { - if (type == FixTypes.CHUNK) { - return (T) fixChunk((CompoundBinaryTag) original, srcVer); - } else if (type == FixTypes.BLOCK_ENTITY) { - return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); - } else if (type == FixTypes.ENTITY) { - return (T) fixEntity((CompoundBinaryTag) 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 CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); - } - - private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); - } - - private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); - } - //FAWE end - - 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( - References.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.contains("Properties", 10)) { - sb.append('['); - net.minecraft.nbt.CompoundTag props = tagCompound.getCompound("Properties"); - sb.append(props - .getAllKeys() - .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, References.BIOME); - } - - private String fixItemType(String key, int srcVer) { - return fixName(key, srcVer, References.ITEM_NAME); - } - - private static String fixName(String key, int srcVer, TypeReference type) { - return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, net.minecraft.nbt.StringTag.valueOf(key)), srcVer, DATA_VERSION) - .getValue().getAsString(); - } - - private final PaperweightAdapter adapter; - - private static final NbtOps OPS_NBT = NbtOps.INSTANCE; - private static final int LEGACY_VERSION = 1343; - private static int DATA_VERSION; - static PaperweightDataConverters 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(References.LEVEL), - PLAYER(References.PLAYER), - CHUNK(References.CHUNK), - BLOCK_ENTITY(References.BLOCK_ENTITY), - ENTITY(References.ENTITY), - ITEM_INSTANCE(References.ITEM_STACK), - OPTIONS(References.OPTIONS), - STRUCTURE(References.STRUCTURE); - - private final TypeReference type; - - LegacyType(TypeReference type) { - this.type = type; - DFU_TO_LEGACY.put(type.typeName(), this); - } - - public TypeReference getDFUType() { - return type; - } - } - - PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { - super(dataVersion); - DATA_VERSION = dataVersion; - INSTANCE = this; - this.adapter = adapter; - registerConverters(); - registerInspectors(); - } - - - // Called after fixers are built and ready for FIXING - @Override - public DataFixer buildUnoptimized() { - return this.fixer = new WrappedDataFixer(DataFixers.getDataFixer()); - } - - @Override - public DataFixer buildOptimized(Executor executor) { - return buildUnoptimized(); - } - - @SuppressWarnings("unchecked") - 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 = PaperweightDataConverters.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 = PaperweightDataConverters.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.contains("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 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, - 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.contains(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.contains(key, 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound.getList(key, 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - nbttaglist.set(j, convert(LegacyType.ITEM_INSTANCE, nbttaglist.getCompound(j), sourceVer, targetVer)); - } - } - - } - - private static class DataConverterEquipment implements DataConverter { - - DataConverterEquipment() { - } - - public int getDataVersion() { - return 100; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("Equipment", 10); - net.minecraft.nbt.ListTag nbttaglist1; - - if (!nbttaglist.isEmpty() && !cmp.contains("HandItems", 10)) { - nbttaglist1 = new net.minecraft.nbt.ListTag(); - nbttaglist1.add(nbttaglist.get(0)); - nbttaglist1.add(new net.minecraft.nbt.CompoundTag()); - cmp.put("HandItems", nbttaglist1); - } - - if (nbttaglist.size() > 1 && !cmp.contains("ArmorItem", 10)) { - nbttaglist1 = new net.minecraft.nbt.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.contains("DropChances", 9)) { - nbttaglist1 = cmp.getList("DropChances", 5); - net.minecraft.nbt.ListTag nbttaglist2; - - if (!cmp.contains("HandDropChances", 10)) { - nbttaglist2 = new net.minecraft.nbt.ListTag(); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(0))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(0.0F)); - cmp.put("HandDropChances", nbttaglist2); - } - - if (!cmp.contains("ArmorDropChances", 10)) { - nbttaglist2 = new net.minecraft.nbt.ListTag(); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(1))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(2))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(3))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(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); - } - } - - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (!cmp.contains("tag", 10)) { - return cmp; - } else { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("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.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 { - - DataInspectorEntity() { - } - - 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.contains("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; - - 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (this.key.equals(new ResourceLocation(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) { - PaperweightDataConverters.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) { - PaperweightDataConverters.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.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"; - // Paper start - materials[409] = "minecraft:prismarine_shard"; - materials[410] = "minecraft:prismarine_crystals"; - materials[411] = "minecraft:rabbit"; - materials[412] = "minecraft:cooked_rabbit"; - materials[413] = "minecraft:rabbit_stew"; - materials[414] = "minecraft:rabbit_foot"; - materials[415] = "minecraft:rabbit_hide"; - materials[416] = "minecraft:armor_stand"; - materials[423] = "minecraft:mutton"; - materials[424] = "minecraft:cooked_mutton"; - materials[425] = "minecraft:banner"; - materials[426] = "minecraft:end_crystal"; - materials[427] = "minecraft:spruce_door"; - materials[428] = "minecraft:birch_door"; - materials[429] = "minecraft:jungle_door"; - materials[430] = "minecraft:acacia_door"; - materials[431] = "minecraft:dark_oak_door"; - materials[432] = "minecraft:chorus_fruit"; - materials[433] = "minecraft:chorus_fruit_popped"; - materials[434] = "minecraft:beetroot"; - materials[435] = "minecraft:beetroot_seeds"; - materials[436] = "minecraft:beetroot_soup"; - materials[437] = "minecraft:dragon_breath"; - materials[438] = "minecraft:splash_potion"; - materials[439] = "minecraft:spectral_arrow"; - materials[440] = "minecraft:tipped_arrow"; - materials[441] = "minecraft:lingering_potion"; - materials[442] = "minecraft:shield"; - materials[443] = "minecraft:elytra"; - materials[444] = "minecraft:spruce_boat"; - materials[445] = "minecraft:birch_boat"; - materials[446] = "minecraft:jungle_boat"; - materials[447] = "minecraft:acacia_boat"; - materials[448] = "minecraft:dark_oak_boat"; - materials[449] = "minecraft:totem_of_undying"; - materials[450] = "minecraft:shulker_shell"; - materials[452] = "minecraft:iron_nugget"; - materials[453] = "minecraft:knowledge_book"; - // Paper end - } - } - - 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.contains("tag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("BlockEntityTag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); - - if (nbttagcompound2.contains("Base", 99)) { - cmp.putShort("Damage", (short) (nbttagcompound2.getShort("Base") & 15)); - if (nbttagcompound1.contains("display", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound3 = nbttagcompound1.getCompound("display"); - - if (nbttagcompound3.contains("Lore", 9)) { - net.minecraft.nbt.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.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 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.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( - "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.contains("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.contains("SpawnPotentials", 9)) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); - - for (int i = 0; i < nbttaglist.size(); ++i) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist.getCompound(i); - - if (nbttagcompound2.contains("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.contains("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.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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("EntityHorse".equals(cmp.getString("id")) && !cmp.contains("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.contains("Facing", 99)) { - Direction enumdirection; - - if (cmp.contains("Direction", 99)) { - enumdirection = Direction.from2DDataValue(cmp.getByte("Direction")); - cmp.putInt("TileX", cmp.getInt("TileX") + enumdirection.getStepX()); - cmp.putInt("TileY", cmp.getInt("TileY") + enumdirection.getStepY()); - cmp.putInt("TileZ", cmp.getInt("TileZ") + enumdirection.getStepZ()); - cmp.remove("Direction"); - if (flag1 && cmp.contains("ItemRotation", 99)) { - cmp.putByte("ItemRotation", (byte) (cmp.getByte("ItemRotation") * 2)); - } - } else { - enumdirection = Direction.from2DDataValue(cmp.getByte("Dir")); - cmp.remove("Dir"); - } - - cmp.putByte("Facing", (byte) enumdirection.get2DDataValue()); - } - - 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) { - net.minecraft.nbt.ListTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - while (cmp.contains("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) { - net.minecraft.nbt.ListTag nbttaglist = new net.minecraft.nbt.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.contains("pages", 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("pages", 8); - - for (int i = 0; i < nbttaglist.size(); ++i) { - String s = nbttaglist.getString(i); - Component object = null; - - if (!"null".equals(s) && !StringUtil.isNullOrEmpty(s)) { - if ((s.charAt(0) != 34 || s.charAt(s.length() - 1) != 34) && (s.charAt(0) != 123 || s.charAt(s.length() - 1) != 125)) { - object = Component.literal(s); - } else { - try { - object = GsonHelper.fromJson(DataConverterSignText.a, s, Component.class, true); - if (object == null) { - object = Component.literal(""); - } - } catch (JsonParseException ignored) { - } - - if (object == null) { - try { - object = Component.Serializer.fromJson(s); - } catch (JsonParseException ignored) { - } - } - - if (object == null) { - try { - object = Component.Serializer.fromJsonLenient(s); - } catch (JsonParseException ignored) { - } - } - - if (object == null) { - object = Component.literal(s); - } - } - } else { - object = Component.literal(""); - } - - nbttaglist.set(i, net.minecraft.nbt.StringTag.valueOf(Component.Serializer.toJson(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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 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 0: - default: - break; - - 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"); - } - - 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 0: - default: - cmp.putString("id", "Horse"); - break; - - 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"); - } - - 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.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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:shulker_box".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("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.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 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(PaperweightDataConverters.class); - - DataConverterBedBlock() { - } - - public int getDataVersion() { - return 1125; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - try { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); - int i = nbttagcompound1.getInt("xPos"); - int j = nbttagcompound1.getInt("zPos"); - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("TileEntities", 10); - net.minecraft.nbt.ListTag nbttaglist1 = nbttagcompound1.getList("Sections", 10); - - for (int k = 0; k < nbttaglist1.size(); ++k) { - net.minecraft.nbt.CompoundTag 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; - net.minecraft.nbt.CompoundTag nbttagcompound3 = new net.minecraft.nbt.CompoundTag(); - - nbttagcompound3.putString("id", "bed"); - nbttagcompound3.putInt("x", i1 + (i << 4)); - nbttagcompound3.putInt("y", j1 + (b0 << 4)); - nbttagcompound3.putInt("z", k1 + (j << 4)); - nbttaglist.add(nbttagcompound3); - } - } - } - } catch (Exception exception) { - DataConverterBedBlock.a.warn("Unable to datafix Bed blocks, level format may be missing tags."); - } - - return cmp; - } - - } - - private static class DataConverterBedItem implements DataConverter { - - DataConverterBedItem() { - } - - public int getDataVersion() { - return 1125; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:bed".equals(cmp.getString("id")) && cmp.getShort("Damage") == 0) { - cmp.putShort("Damage", (short) DyeColor.RED.getId()); - } - - return cmp; - } - - } - - private static class DataConverterSignText implements DataConverter { - - public static final Gson a = new GsonBuilder().registerTypeAdapter(Component.class, new JsonDeserializer() { - MutableComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws - JsonParseException { - if (jsonelement.isJsonPrimitive()) { - return Component.literal(jsonelement.getAsString()); - } else if (jsonelement.isJsonArray()) { - JsonArray jsonarray = jsonelement.getAsJsonArray(); - MutableComponent ichatbasecomponent = null; - - for (final JsonElement jsonelement1 : jsonarray) { - MutableComponent ichatbasecomponent1 = this.a( - jsonelement1, - jsonelement1.getClass(), - jsondeserializationcontext - ); - - if (ichatbasecomponent == null) { - ichatbasecomponent = ichatbasecomponent1; - } else { - ichatbasecomponent.append(ichatbasecomponent1); - } - } - - return ichatbasecomponent; - } 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); - Component object = null; - - if (!"null".equals(s1) && !StringUtil.isNullOrEmpty(s1)) { - if ((s1.charAt(0) != 34 || s1.charAt(s1.length() - 1) != 34) && (s1.charAt(0) != 123 || s1.charAt(s1.length() - 1) != 125)) { - object = Component.literal(s1); - } else { - try { - object = GsonHelper.fromJson(DataConverterSignText.a, s1, Component.class, true); - if (object == null) { - object = Component.literal(""); - } - } catch (JsonParseException ignored) { - } - - if (object == null) { - try { - object = Component.Serializer.fromJson(s1); - } catch (JsonParseException ignored) { - } - } - - if (object == null) { - try { - object = Component.Serializer.fromJsonLenient(s1); - } catch (JsonParseException ignored) { - } - } - - if (object == null) { - object = Component.literal(s1); - } - } - } else { - object = Component.literal(""); - } - - nbttagcompound.putString(s, Component.Serializer.toJson(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.contains("RootVehicle", 10)) { - net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - net.minecraft.nbt.ListTag nbttaglist; - int j; - net.minecraft.nbt.CompoundTag nbttagcompound1; - - if (cmp.contains("entities", 9)) { - nbttaglist = cmp.getList("entities", 10); - - for (j = 0; j < nbttaglist.size(); ++j) { - nbttagcompound1 = (net.minecraft.nbt.CompoundTag) 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 = (net.minecraft.nbt.CompoundTag) 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (cmp.contains("Level", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); - net.minecraft.nbt.ListTag 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, - (net.minecraft.nbt.CompoundTag) 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, - (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.contains("Passengers", 9)) { - net.minecraft.nbt.ListTag 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 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.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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (entityVillager.equals(new ResourceLocation(cmp.getString("id"))) && cmp.contains("Offers", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Offers"); - - if (nbttagcompound1.contains("Recipes", 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("Recipes", 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (tileEntityMobSpawner.equals(new ResourceLocation(cmp.getString("id")))) { - if (cmp.contains("SpawnPotentials", 9)) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R1/PaperweightFakePlayer.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R1/PaperweightFakePlayer.java deleted file mode 100644 index 43964319c..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R1/PaperweightFakePlayer.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R1; - -import com.mojang.authlib.GameProfile; -import net.minecraft.network.chat.ChatType; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ServerboundClientInformationPacket; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.stats.Stat; -import net.minecraft.world.MenuProvider; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.block.entity.SignBlockEntity; -import net.minecraft.world.phys.Vec3; -import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; - -import java.util.OptionalInt; -import java.util.UUID; - -class PaperweightFakePlayer extends ServerPlayer { - - private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile( - UUID.nameUUIDFromBytes("worldedit".getBytes()), - "[WorldEdit]" - ); - private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D); - - PaperweightFakePlayer(ServerLevel world) { - super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE, null); - } - - @Override - public Vec3 position() { - return ORIGIN; - } - - @Override - public void tick() { - } - - @Override - public void die(DamageSource damagesource) { - } - - @Override - public Entity changeDimension(ServerLevel worldserver, TeleportCause cause) { - return this; - } - - @Override - public OptionalInt openMenu(MenuProvider factory) { - return OptionalInt.empty(); - } - - @Override - public void updateOptions(ServerboundClientInformationPacket packet) { - } - - @Override - public void displayClientMessage(Component message, boolean actionBar) { - } - - @Override - public void awardStat(Stat stat, int amount) { - } - - @Override - public void awardStat(Stat stat) { - } - - @Override - public boolean isInvulnerableTo(DamageSource damageSource) { - return true; - } - - @Override - public void openTextEdit(SignBlockEntity sign) { - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R1/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R1/PaperweightWorldNativeAccess.java deleted file mode 100644 index 3f748bb9d..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R1/PaperweightWorldNativeAccess.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R1; - -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.world.block.BlockState; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.chunk.LevelChunk; -import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData; -import org.bukkit.event.block.BlockPhysicsEvent; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.util.Objects; - -public class PaperweightWorldNativeAccess implements - WorldNativeAccess { - - private static final int UPDATE = 1; - private static final int NOTIFY = 2; - - private final PaperweightAdapter adapter; - private final WeakReference world; - private SideEffectSet sideEffectSet; - - public PaperweightWorldNativeAccess(PaperweightAdapter adapter, WeakReference world) { - this.adapter = adapter; - this.world = world; - } - - private ServerLevel getWorld() { - return Objects.requireNonNull(world.get(), "The reference to the world was lost"); - } - - @Override - public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { - this.sideEffectSet = sideEffectSet; - } - - @Override - public LevelChunk getChunk(int x, int z) { - return getWorld().getChunk(x, z); - } - - @Override - public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) { - int stateId = BlockStateIdAccess.getBlockStateId(state); - return BlockStateIdAccess.isValidInternalId(stateId) - ? Block.stateById(stateId) - : ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk chunk, BlockPos position) { - return chunk.getBlockState(position); - } - - @Nullable - @Override - public net.minecraft.world.level.block.state.BlockState setBlockState( - LevelChunk chunk, - BlockPos position, - net.minecraft.world.level.block.state.BlockState state - ) { - return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE)); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition( - net.minecraft.world.level.block.state.BlockState block, - BlockPos position - ) { - return Block.updateFromNeighbourShapes(block, getWorld(), position); - } - - @Override - public BlockPos getPosition(int x, int y, int z) { - return new BlockPos(x, y, z); - } - - @Override - public void updateLightingForBlock(BlockPos position) { - getWorld().getChunkSource().getLightEngine().checkBlock(position); - } - - @Override - public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { - return false; - } - - @Override - public void notifyBlockUpdate( - LevelChunk chunk, - BlockPos position, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { - getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY); - } - } - - @Override - public boolean isChunkTicking(LevelChunk chunk) { - return chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); - } - - @Override - public void markBlockChanged(LevelChunk chunk, BlockPos position) { - if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { - getWorld().getChunkSource().blockChanged(position); - } - } - - @Override - public void notifyNeighbors( - BlockPos pos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - ServerLevel world = getWorld(); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - world.updateNeighborsAt(pos, oldState.getBlock()); - } else { - // When we don't want events, manually run the physics without them. - Block block = oldState.getBlock(); - fireNeighborChanged(pos, world, block, pos.west()); - fireNeighborChanged(pos, world, block, pos.east()); - fireNeighborChanged(pos, world, block, pos.below()); - fireNeighborChanged(pos, world, block, pos.above()); - fireNeighborChanged(pos, world, block, pos.north()); - fireNeighborChanged(pos, world, block, pos.south()); - } - if (newState.hasAnalogOutputSignal()) { - world.updateNeighbourForOutputSignal(pos, newState.getBlock()); - } - } - - @SuppressWarnings("deprecation") - private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { - world.getBlockState(neighborPos).neighborChanged(world, neighborPos, block, pos, false); - } - - @Override - public void updateNeighbors( - BlockPos pos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState, - int recursionLimit - ) { - ServerLevel world = getWorld(); - // a == updateNeighbors - // b == updateDiagonalNeighbors - oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - CraftWorld craftWorld = world.getWorld(); - BlockPhysicsEvent event = new BlockPhysicsEvent( - craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), - CraftBlockData.fromData(newState) - ); - world.getCraftServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - } - newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit); - newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); - } - - @Override - public void onBlockStateChange( - BlockPos pos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - getWorld().onBlockStateChange(pos, oldState, newState); - } - - @Override - public void flush() { - - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightBlockMaterial.java deleted file mode 100644 index 812cd4e24..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightBlockMaterial.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1; - -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.util.ReflectionUtil; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.world.registry.BlockMaterial; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.EmptyBlockGetter; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.EntityBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.Material; -import net.minecraft.world.level.material.PushReaction; -import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData; - -public class PaperweightBlockMaterial implements BlockMaterial { - - private final Block block; - private final BlockState blockState; - private final Material material; - private final boolean isTranslucent; - private final CraftBlockData craftBlockData; - private final org.bukkit.Material craftMaterial; - private final int opacity; - private final CompoundTag tile; - - public PaperweightBlockMaterial(Block block) { - this(block, block.defaultBlockState()); - } - - public PaperweightBlockMaterial(Block block, BlockState blockState) { - this.block = block; - this.blockState = blockState; - this.material = blockState.getMaterial(); - this.craftBlockData = CraftBlockData.fromData(blockState); - this.craftMaterial = craftBlockData.getMaterial(); - BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, Refraction.pickName( - "properties", "aO")); - this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo, - Refraction.pickName("canOcclude", "n") - ); - opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); - BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity( - BlockPos.ZERO, - blockState - ); - tile = tileEntity == null - ? null - : new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); - } - - public Block getBlock() { - return block; - } - - public BlockState getState() { - return blockState; - } - - public CraftBlockData getCraftBlockData() { - return craftBlockData; - } - - public Material getMaterial() { - return material; - } - - @Override - public boolean isAir() { - return blockState.isAir(); - } - - @Override - public boolean isFullCube() { - return craftMaterial.isOccluding(); - } - - @Override - public boolean isOpaque() { - return material.isSolidBlocking(); - } - - @Override - public boolean isPowerSource() { - return blockState.isSignalSource(); - } - - @Override - public boolean isLiquid() { - return material.isLiquid(); - } - - @Override - public boolean isSolid() { - return material.isSolid(); - } - - @Override - public float getHardness() { - return craftBlockData.getState().destroySpeed; - } - - @Override - public float getResistance() { - return block.getExplosionResistance(); - } - - @Override - public float getSlipperiness() { - return block.getFriction(); - } - - @Override - public int getLightValue() { - return blockState.getLightEmission(); - } - - @Override - public int getLightOpacity() { - return opacity; - } - - @Override - public boolean isFragileWhenPushed() { - return material.getPushReaction() == PushReaction.DESTROY; - } - - @Override - public boolean isUnpushable() { - return material.getPushReaction() == PushReaction.BLOCK; - } - - @Override - public boolean isTicksRandomly() { - return block.isRandomlyTicking(blockState); - } - - @Override - public boolean isMovementBlocker() { - return material.isSolid(); - } - - @Override - public boolean isBurnable() { - return material.isFlammable(); - } - - @Override - public boolean isToolRequired() { - // Removed in 1.16.1, this is not present in higher versions - return false; - } - - @Override - public boolean isReplacedDuringPlacement() { - return material.isReplaceable(); - } - - @Override - public boolean isTranslucent() { - return isTranslucent; - } - - @Override - public boolean hasContainer() { - return block instanceof EntityBlock; - } - - @Override - public boolean isTile() { - return block instanceof EntityBlock; - } - - @Override - public CompoundTag getDefaultTile() { - return tile; - } - - @Override - public int getMapColor() { - // rgb field - return material.getColor().col; - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightFaweAdapter.java deleted file mode 100644 index b9aa9cf7f..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightFaweAdapter.java +++ /dev/null @@ -1,701 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1; - -import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; -import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter; -import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.entity.LazyBaseEntity; -import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IBatchProcessor; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; -import com.fastasyncworldedit.core.util.NbtUtils; -import com.fastasyncworldedit.core.util.TaskManager; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.blocks.TileEntityBlock; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.BukkitWorld; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R1.PaperweightAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1.regen.PaperweightRegen; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; -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.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.TreeGenerator; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; -import com.sk89q.worldedit.world.RegenOptions; -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.block.BlockType; -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.item.ItemType; -import com.sk89q.worldedit.world.registry.BlockMaterial; -import io.papermc.lib.PaperLib; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Registry; -import net.minecraft.core.WritableRegistry; -import net.minecraft.nbt.IntTag; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.util.StringRepresentable; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.DirectionProperty; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.TreeType; -import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_19_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_19_R1.CraftServer; -import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R1.block.CraftBlockState; -import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_19_R1.util.CraftNamespacedKey; -import org.bukkit.entity.Player; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.OptionalInt; -import java.util.Set; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements - IDelegateBukkitImplAdapter { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; - - static { - try { - CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE = ChunkHolder.class.getDeclaredMethod("wasAccessibleSinceLastSave"); - } catch (NoSuchMethodException ignored) { // may not be present in newer paper versions - } - } - - private final PaperweightAdapter parent; - // ------------------------------------------------------------------------ - // Code that may break between versions of Minecraft - // ------------------------------------------------------------------------ - private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil(); - private char[] ibdToStateOrdinal = null; - private int[] ordinalToIbdID = null; - private boolean initialised = false; - private Map>> allBlockProperties = null; - - public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { - this.parent = new PaperweightAdapter(); - } - - @Nullable - private static String getEntityId(Entity entity) { - ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType()); - return resourceLocation == null ? null : resourceLocation.toString(); - } - - private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { - entity.save(compoundTag); - } - - @Override - public BukkitImplAdapter getParent() { - return parent; - } - - private synchronized boolean init() { - if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) { - return false; - } - ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size - ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size - for (int i = 0; i < ibdToStateOrdinal.length; i++) { - BlockState blockState = BlockTypesCache.states[i]; - PaperweightBlockMaterial material = (PaperweightBlockMaterial) blockState.getMaterial(); - int id = Block.BLOCK_STATE_REGISTRY.getId(material.getState()); - char ordinal = blockState.getOrdinalChar(); - ibdToStateOrdinal[id] = ordinal; - ordinalToIbdID[ordinal] = id; - } - Map>> properties = new HashMap<>(); - try { - for (Field field : BlockStateProperties.class.getDeclaredFields()) { - Object obj = field.get(null); - if (!(obj instanceof net.minecraft.world.level.block.state.properties.Property state)) { - continue; - } - Property property; - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - property = new BooleanProperty( - state.getName(), - (List) ImmutableList.copyOf(state.getPossibleValues()) - ); - } else if (state instanceof DirectionProperty) { - property = new DirectionalProperty( - state.getName(), - state - .getPossibleValues() - .stream() - .map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase())) - .collect(Collectors.toList()) - ); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - property = new EnumProperty( - state.getName(), - state - .getPossibleValues() - .stream() - .map(e -> ((StringRepresentable) e).getSerializedName()) - .collect(Collectors.toList()) - ); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - property = new IntegerProperty( - state.getName(), - (List) ImmutableList.copyOf(state.getPossibleValues()) - ); - } else { - throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state - .getClass() - .getSimpleName()); - } - properties.compute(property.getName().toLowerCase(Locale.ROOT), (k, v) -> { - if (v == null) { - v = new ArrayList<>(Collections.singletonList(property)); - } else { - v.add(property); - } - return v; - }); - } - } catch (IllegalAccessException e) { - e.printStackTrace(); - } finally { - allBlockProperties = ImmutableMap.copyOf(properties); - } - initialised = true; - return true; - } - - @Override - public BlockMaterial getMaterial(BlockType blockType) { - Block block = getBlock(blockType); - return new PaperweightBlockMaterial(block); - } - - @Override - public synchronized BlockMaterial getMaterial(BlockState state) { - net.minecraft.world.level.block.state.BlockState blockState = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState(); - return new PaperweightBlockMaterial(blockState.getBlock(), blockState); - } - - public Block getBlock(BlockType blockType) { - return Registry.BLOCK.get(new ResourceLocation(blockType.getNamespace(), blockType.getResource())); - } - - @Deprecated - @Override - public BlockState getBlock(Location location) { - Preconditions.checkNotNull(location); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - BlockState state = adapt(blockData); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - return state; - } - - @Override - public BaseBlock getFullBlock(final Location location) { - Preconditions.checkNotNull(location); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - BlockState state = adapt(blockData); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - if (state.getBlockType().getMaterial().hasContainer()) { - - // Read the NBT data - BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); - if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); - return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); - } - } - - return state.toBaseBlock(); - } - - @Override - public Set getSupportedSideEffects() { - return SideEffectSet.defaults().getSideEffectsToApply(); - } - - public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) { - CraftChunk craftChunk = (CraftChunk) chunk; - LevelChunk levelChunk = craftChunk.getHandle(); - Level level = levelChunk.getLevel(); - - BlockPos blockPos = new BlockPos(x, y, z); - net.minecraft.world.level.block.state.BlockState blockState = ((PaperweightBlockMaterial) state.getMaterial()).getState(); - LevelChunkSection[] levelChunkSections = levelChunk.getSections(); - int y4 = y >> 4; - LevelChunkSection section = levelChunkSections[y4]; - - net.minecraft.world.level.block.state.BlockState existing; - if (section == null) { - existing = ((PaperweightBlockMaterial) BlockTypes.AIR.getDefaultState().getMaterial()).getState(); - } else { - existing = section.getBlockState(x & 15, y & 15, z & 15); - } - - levelChunk.removeBlockEntity(blockPos); // Force delete the old tile entity - - CompoundBinaryTag compoundTag = state instanceof BaseBlock ? state.getNbt() : null; - if (compoundTag != null || existing instanceof TileEntityBlock) { - level.setBlock(blockPos, blockState, 0); - // remove tile - if (compoundTag != null) { - // We will assume that the tile entity was created for us, - // though we do not do this on the Forge version - BlockEntity blockEntity = level.getBlockEntity(blockPos); - if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(compoundTag); - tag.put("x", IntTag.valueOf(x)); - tag.put("y", IntTag.valueOf(y)); - tag.put("z", IntTag.valueOf(z)); - blockEntity.load(tag); // readTagIntoTileEntity - load data - } - } - } else { - if (existing == blockState) { - return true; - } - levelChunk.setBlockState(blockPos, blockState, false); - } - if (update) { - level.getMinecraftWorld().sendBlockUpdated(blockPos, existing, blockState, 0); - } - return true; - } - - @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightFaweWorldNativeAccess( - this, - new WeakReference<>(((CraftWorld) world).getHandle()) - ); - } - - @Override - public BaseEntity getEntity(org.bukkit.entity.Entity entity) { - Preconditions.checkNotNull(entity); - - CraftEntity craftEntity = ((CraftEntity) entity); - Entity mcEntity = craftEntity.getHandle(); - - String id = getEntityId(mcEntity); - - if (id != null) { - EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); - Supplier saveTag = () -> { - final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); - readEntityIntoTag(mcEntity, minecraftTag); - //add Id for AbstractChangeSet to work - final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); - final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); - tags.put("Id", StringBinaryTag.of(id)); - return CompoundBinaryTag.from(tags); - }; - return new LazyBaseEntity(type, saveTag); - } else { - return null; - } - } - - @Override - public Component getRichBlockName(BlockType blockType) { - return parent.getRichBlockName(blockType); - } - - @Override - public Component getRichItemName(ItemType itemType) { - return parent.getRichItemName(itemType); - } - - @Override - public Component getRichItemName(BaseItemStack itemStack) { - return parent.getRichItemName(itemStack); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockState state) { - PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); - net.minecraft.world.level.block.state.BlockState mcState = material.getCraftBlockData().getState(); - return OptionalInt.of(Block.BLOCK_STATE_REGISTRY.getId(mcState)); - } - - @Override - public BlockState adapt(BlockData blockData) { - CraftBlockData cbd = ((CraftBlockData) blockData); - net.minecraft.world.level.block.state.BlockState ibd = cbd.getState(); - return adapt(ibd); - } - - public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) { - return BlockTypesCache.states[adaptToChar(blockState)]; - } - - public char adaptToChar(net.minecraft.world.level.block.state.BlockState blockState) { - int id = Block.BLOCK_STATE_REGISTRY.getId(blockState); - if (initialised) { - return ibdToStateOrdinal[id]; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - try { - init(); - return ibdToStateOrdinal[id]; - } catch (ArrayIndexOutOfBoundsException e1) { - LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!", - blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1 - ); - return BlockTypesCache.ReservedIDs.AIR; - } - } - } - - public char ibdIDToOrdinal(int id) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - init(); - return ibdToStateOrdinal[id]; - } - } - - @Override - public char[] getIbdToStateOrdinal() { - if (initialised) { - return ibdToStateOrdinal; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal; - } - init(); - return ibdToStateOrdinal; - } - } - - public int ordinalToIbdID(char ordinal) { - if (initialised) { - return ordinalToIbdID[ordinal]; - } - synchronized (this) { - if (initialised) { - return ordinalToIbdID[ordinal]; - } - init(); - return ordinalToIbdID[ordinal]; - } - } - - @Override - public int[] getOrdinalToIbdID() { - if (initialised) { - return ordinalToIbdID; - } - synchronized (this) { - if (initialised) { - return ordinalToIbdID; - } - init(); - return ordinalToIbdID; - } - } - - @Override - public > BlockData adapt(B state) { - PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); - return material.getCraftBlockData(); - } - - @Override - public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); - ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); - if (map != null && wasAccessibleSinceLastSave(map)) { - boolean flag = false; - // PlayerChunk.d players = map.players; - Stream stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag) - */ Stream.empty(); - - ServerPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle(); - stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer) - .forEach(entityPlayer -> { - synchronized (chunkPacket) { - ClientboundLevelChunkWithLightPacket nmsPacket = (ClientboundLevelChunkWithLightPacket) chunkPacket.getNativePacket(); - if (nmsPacket == null) { - nmsPacket = mapUtil.create(this, chunkPacket); - chunkPacket.setNativePacket(nmsPacket); - } - try { - FaweCache.INSTANCE.CHUNK_FLAG.get().set(true); - entityPlayer.connection.send(nmsPacket); - } finally { - FaweCache.INSTANCE.CHUNK_FLAG.get().set(false); - } - } - }); - } - } - - @Override - public Map> getProperties(BlockType blockType) { - return getParent().getProperties(blockType); - } - - @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) { - int internalId = BlockStateIdAccess.getBlockStateId(blockState); - net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); - return blockState1.hasPostProcess( - ((CraftWorld) world).getHandle(), - new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) - ); - } - - @Override - public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { - ItemStack stack = new ItemStack( - Registry.ITEM.get(ResourceLocation.tryParse(baseItemStack.getType().getId())), - baseItemStack.getAmount() - ); - stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()))); - return CraftItemStack.asCraftMirror(stack); - } - - @Override - public boolean generateTree( - TreeGenerator.TreeType treeType, EditSession editSession, BlockVector3 blockVector3, - org.bukkit.World bukkitWorld - ) { - TreeType bukkitType = BukkitWorld.toBukkitTreeType(treeType); - if (bukkitType == TreeType.CHORUS_PLANT) { - blockVector3 = blockVector3.add( - 0, - 1, - 0 - ); // bukkit skips the feature gen which does this offset normally, so we have to add it back - } - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - final BlockVector3 finalBlockVector = blockVector3; - // Sync to main thread to ensure no clashes occur - Map placed = TaskManager.taskManager().sync(() -> { - serverLevel.captureTreeGeneration = true; - serverLevel.captureBlockStates = true; - try { - if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) { - return null; - } - return ImmutableMap.copyOf(serverLevel.capturedBlockStates); - } finally { - serverLevel.captureBlockStates = false; - serverLevel.captureTreeGeneration = false; - serverLevel.capturedBlockStates.clear(); - } - }); - if (placed == null || placed.isEmpty()) { - return false; - } - for (CraftBlockState craftBlockState : placed.values()) { - if (craftBlockState == null || craftBlockState.getType() == Material.AIR) { - continue; - } - editSession.setBlock(craftBlockState.getX(), craftBlockState.getY(), craftBlockState.getZ(), - BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData()) - ); - } - return true; - } - - @Override - public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { - final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); - final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); - weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); - return weStack; - } - - @Override - public Tag toNative(net.minecraft.nbt.Tag foreign) { - return parent.toNative(foreign); - } - - @Override - public net.minecraft.nbt.Tag fromNative(Tag foreign) { - if (foreign instanceof PaperweightLazyCompoundTag) { - return ((PaperweightLazyCompoundTag) foreign).get(); - } - return parent.fromNative(foreign); - } - - @Override - public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { - return new PaperweightRegen(bukkitWorld, region, target, options).regenerate(); - } - - @Override - public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { - return new PaperweightGetBlocks(world, chunkX, chunkZ); - } - - @Override - public int getInternalBiomeId(BiomeType biomeType) { - final Registry registry = MinecraftServer - .getServer() - .registryAccess() - .ownedRegistryOrThrow(Registry.BIOME_REGISTRY); - ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.getId()); - Biome biome = registry.get(resourceLocation); - return registry.getId(biome); - } - - @Override - public Iterable getRegisteredBiomes() { - WritableRegistry biomeRegistry = (WritableRegistry) ((CraftServer) Bukkit.getServer()) - .getServer() - .registryAccess() - .ownedRegistryOrThrow( - Registry.BIOME_REGISTRY); - List keys = biomeRegistry.stream() - .map(biomeRegistry::getKey).filter(Objects::nonNull).toList(); - List namespacedKeys = new ArrayList<>(); - for (ResourceLocation key : keys) { - try { - namespacedKeys.add(CraftNamespacedKey.fromMinecraft(key)); - } catch (IllegalArgumentException e) { - LOGGER.error("Error converting biome key {}", key.toString(), e); - } - } - return namespacedKeys; - } - - @Override - public RelighterFactory getRelighterFactory() { - if (PaperLib.isPaper()) { - return new PaperweightStarlightRelighterFactory(); - } else { - return new NMSRelighterFactory(); - } - } - - @Override - public Map>> getAllProperties() { - if (initialised) { - return allBlockProperties; - } - synchronized (this) { - if (initialised) { - return allBlockProperties; - } - init(); - return allBlockProperties; - } - } - - @Override - public IBatchProcessor getTickingPostProcessor() { - return new PaperweightPostProcessor(); - } - - private boolean wasAccessibleSinceLastSave(ChunkHolder holder) { - if (!PaperLib.isPaper() || !PaperweightPlatformAdapter.POST_CHUNK_REWRITE) { - try { - return (boolean) CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE.invoke(holder); - } catch (IllegalAccessException | InvocationTargetException ignored) { - // fall-through - } - } - // Papers new chunk system has no related replacement - therefor we assume true. - return true; - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightFaweWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightFaweWorldNativeAccess.java deleted file mode 100644 index 0e7f6ea0c..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightFaweWorldNativeAccess.java +++ /dev/null @@ -1,286 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1; - -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.math.IntPair; -import com.fastasyncworldedit.core.util.TaskManager; -import com.fastasyncworldedit.core.util.task.RunnableVal; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.world.block.BlockState; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.LevelChunk; -import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData; -import org.bukkit.event.block.BlockPhysicsEvent; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.util.Collections; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; - -public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess { - - private static final int UPDATE = 1; - private static final int NOTIFY = 2; - private static final Direction[] NEIGHBOUR_ORDER = { - Direction.EAST, - Direction.WEST, - Direction.DOWN, - Direction.UP, - Direction.NORTH, - Direction.SOUTH - }; - private final PaperweightFaweAdapter paperweightFaweAdapter; - private final WeakReference level; - private final AtomicInteger lastTick; - private final Set cachedChanges = new HashSet<>(); - private final Set cachedChunksToSend = new HashSet<>(); - private SideEffectSet sideEffectSet; - - public PaperweightFaweWorldNativeAccess(PaperweightFaweAdapter paperweightFaweAdapter, WeakReference level) { - this.paperweightFaweAdapter = paperweightFaweAdapter; - this.level = level; - // Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging. - // - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway. - this.lastTick = new AtomicInteger(MinecraftServer.currentTick); - } - - private Level getLevel() { - return Objects.requireNonNull(level.get(), "The reference to the world was lost"); - } - - @Override - public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { - this.sideEffectSet = sideEffectSet; - } - - @Override - public LevelChunk getChunk(int x, int z) { - return getLevel().getChunk(x, z); - } - - @Override - public net.minecraft.world.level.block.state.BlockState toNative(BlockState blockState) { - int stateId = paperweightFaweAdapter.ordinalToIbdID(blockState.getOrdinalChar()); - return BlockStateIdAccess.isValidInternalId(stateId) - ? Block.stateById(stateId) - : ((CraftBlockData) BukkitAdapter.adapt(blockState)).getState(); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk levelChunk, BlockPos blockPos) { - return levelChunk.getBlockState(blockPos); - } - - @Nullable - @Override - public synchronized net.minecraft.world.level.block.state.BlockState setBlockState( - LevelChunk levelChunk, BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState blockState - ) { - int currentTick = MinecraftServer.currentTick; - if (Fawe.isMainThread()) { - return levelChunk.setBlockState(blockPos, blockState, - this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE) - ); - } - // Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( ) - cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState)); - cachedChunksToSend.add(new IntPair(levelChunk.bukkitChunk.getX(), levelChunk.bukkitChunk.getZ())); - boolean nextTick = lastTick.get() > currentTick; - if (nextTick || cachedChanges.size() >= 1024) { - if (nextTick) { - lastTick.set(currentTick); - } - flushAsync(nextTick); - } - return blockState; - } - - @Override - public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition( - net.minecraft.world.level.block.state.BlockState blockState, - BlockPos blockPos - ) { - return Block.updateFromNeighbourShapes(blockState, getLevel(), blockPos); - } - - @Override - public BlockPos getPosition(int x, int y, int z) { - return new BlockPos(x, y, z); - } - - @Override - public void updateLightingForBlock(BlockPos blockPos) { - getLevel().getChunkSource().getLightEngine().checkBlock(blockPos); - } - - @Override - public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) { - // We will assume that the tile entity was created for us, - // though we do not do this on the other versions - BlockEntity blockEntity = getLevel().getBlockEntity(blockPos); - if (blockEntity == null) { - return false; - } - net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeBinary(tag); - blockEntity.load((CompoundTag) nativeTag); - return true; - } - - @Override - public void notifyBlockUpdate( - LevelChunk levelChunk, BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { - getLevel().sendBlockUpdated(blockPos, oldState, newState, UPDATE | NOTIFY); - } - } - - @Override - public boolean isChunkTicking(LevelChunk levelChunk) { - return levelChunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); - } - - @Override - public void markBlockChanged(LevelChunk levelChunk, BlockPos blockPos) { - if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { - ((ServerChunkCache) getLevel().getChunkSource()).blockChanged(blockPos); - } - } - - @Override - public void notifyNeighbors( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - Level level = getLevel(); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - level.blockUpdated(blockPos, oldState.getBlock()); - } else { - // When we don't want events, manually run the physics without them. - // Un-nest neighbour updating - for (Direction direction : NEIGHBOUR_ORDER) { - BlockPos shifted = blockPos.relative(direction); - level.getBlockState(shifted).neighborChanged(level, shifted, oldState.getBlock(), blockPos, false); - } - } - if (newState.hasAnalogOutputSignal()) { - level.updateNeighbourForOutputSignal(blockPos, newState.getBlock()); - } - } - - @Override - public void updateNeighbors( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState, - int recursionLimit - ) { - Level level = getLevel(); - // a == updateNeighbors - // b == updateDiagonalNeighbors - oldState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - CraftWorld craftWorld = level.getWorld(); - if (craftWorld != null) { - BlockPhysicsEvent event = new BlockPhysicsEvent( - craftWorld.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()), - CraftBlockData.fromData(newState) - ); - level.getCraftServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - } - } - newState.triggerEvent(level, blockPos, NOTIFY, recursionLimit); - newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); - } - - @Override - public void onBlockStateChange( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - getLevel().onBlockStateChange(blockPos, oldState, newState); - } - - private synchronized void flushAsync(final boolean sendChunks) { - final Set changes = Set.copyOf(cachedChanges); - cachedChanges.clear(); - final Set toSend; - if (sendChunks) { - toSend = Set.copyOf(cachedChunksToSend); - cachedChunksToSend.clear(); - } else { - toSend = Collections.emptySet(); - } - RunnableVal runnableVal = new RunnableVal<>() { - @Override - public void run(Object value) { - changes.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, - sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) - )); - if (!sendChunks) { - return; - } - for (IntPair chunk : toSend) { - PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); - } - } - }; - TaskManager.taskManager().async(() -> TaskManager.taskManager().sync(runnableVal)); - } - - @Override - public synchronized void flush() { - RunnableVal runnableVal = new RunnableVal<>() { - @Override - public void run(Object value) { - cachedChanges.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, - sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) - )); - for (IntPair chunk : cachedChunksToSend) { - PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); - } - } - }; - if (Fawe.isMainThread()) { - runnableVal.run(); - } else { - TaskManager.taskManager().sync(runnableVal); - } - cachedChanges.clear(); - cachedChunksToSend.clear(); - } - - private record CachedChange( - LevelChunk levelChunk, - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState blockState - ) { - - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightGetBlocks.java deleted file mode 100644 index 6466ea828..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightGetBlocks.java +++ /dev/null @@ -1,1164 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1; - -import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; -import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; -import com.fastasyncworldedit.core.math.BitArrayUnstretched; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.fastasyncworldedit.core.queue.implementation.QueueHandler; -import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.collection.AdaptedMap; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.internal.Constants; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.BiomeTypes; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import io.papermc.lib.PaperLib; -import io.papermc.paper.event.block.BeaconDeactivatedEvent; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.IdMap; -import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; -import net.minecraft.nbt.IntTag; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.util.BitStorage; -import net.minecraft.util.ZeroBitStorage; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.entity.BeaconBlockEntity; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.HashMapPalette; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.LinearPalette; -import net.minecraft.world.level.chunk.Palette; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.level.lighting.LevelLightEngine; -import org.apache.logging.log4j.Logger; -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R1.block.CraftBlock; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import javax.annotation.Nonnull; -import java.util.AbstractSet; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.Future; -import java.util.concurrent.Semaphore; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.function.Function; -import java.util.stream.Collectors; - -public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private static final Function posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); - private static final Function nmsTile2We = - tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); - private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin - .getInstance() - .getBukkitImplAdapter()); - private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); - private final ServerLevel serverLevel; - private final int chunkX; - private final int chunkZ; - private final int minHeight; - private final int maxHeight; - private final int minSectionPosition; - private final int maxSectionPosition; - private final Registry biomeRegistry; - private final IdMap> biomeHolderIdMap; - private LevelChunkSection[] sections; - private LevelChunk levelChunk; - private DataLayer[] blockLight; - private DataLayer[] skyLight; - private boolean createCopy = false; - private PaperweightGetBlocks_Copy copy = null; - private boolean forceLoadSections = true; - private boolean lightUpdate = false; - - public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { - this(((CraftWorld) world).getHandle(), chunkX, chunkZ); - } - - public PaperweightGetBlocks(ServerLevel serverLevel, int chunkX, int chunkZ) { - super(serverLevel.getMinBuildHeight() >> 4, (serverLevel.getMaxBuildHeight() - 1) >> 4); - this.serverLevel = serverLevel; - this.chunkX = chunkX; - this.chunkZ = chunkZ; - this.minHeight = serverLevel.getMinBuildHeight(); - this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. - this.minSectionPosition = minHeight >> 4; - this.maxSectionPosition = maxHeight >> 4; - this.skyLight = new DataLayer[getSectionCount()]; - this.blockLight = new DataLayer[getSectionCount()]; - this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); - this.biomeHolderIdMap = biomeRegistry.asHolderIdMap(); - } - - public int getChunkX() { - return chunkX; - } - - public int getChunkZ() { - return chunkZ; - } - - @Override - public boolean isCreateCopy() { - return createCopy; - } - - @Override - public void setCreateCopy(boolean createCopy) { - this.createCopy = createCopy; - } - - @Override - public IChunkGet getCopy() { - return copy; - } - - @Override - public void setLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { - if (light != null) { - lightUpdate = true; - try { - fillLightNibble(light, LightLayer.BLOCK, minSectionPosition, maxSectionPosition); - } catch (Throwable e) { - e.printStackTrace(); - } - } - } - - @Override - public void setSkyLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { - if (light != null) { - lightUpdate = true; - try { - fillLightNibble(light, LightLayer.SKY, minSectionPosition, maxSectionPosition); - } catch (Throwable e) { - e.printStackTrace(); - } - } - } - - @Override - public void setHeightmapToGet(HeightMapType type, int[] data) { - // height + 1 to match server internal - BitArrayUnstretched bitArray = new BitArrayUnstretched(MathMan.log2nlz(getChunk().getHeight() + 1), 256); - bitArray.fromRaw(data); - Heightmap.Types nativeType = Heightmap.Types.valueOf(type.name()); - Heightmap heightMap = getChunk().heightmaps.get(nativeType); - heightMap.setRawData(getChunk(), nativeType, bitArray.getData()); - } - - @Override - public int getMaxY() { - return maxHeight; - } - - @Override - public int getMinY() { - return minHeight; - } - - @Override - public BiomeType getBiomeType(int x, int y, int z) { - LevelChunkSection section = getSections(false)[(y >> 4) - getMinSectionPosition()]; - Holder biomes = section.getNoiseBiome(x >> 2, (y & 15) >> 2, z >> 2); - return PaperweightPlatformAdapter.adapt(biomes, serverLevel); - } - - @Override - public void removeSectionLighting(int layer, boolean sky) { - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.BLOCK).getDataLayerData( - sectionPos); - if (dataLayer != null) { - lightUpdate = true; - synchronized (dataLayer) { - byte[] bytes = dataLayer.getData(); - Arrays.fill(bytes, (byte) 0); - } - } - if (sky) { - SectionPos sectionPos1 = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer1 = serverLevel - .getChunkSource() - .getLightEngine() - .getLayerListener(LightLayer.SKY) - .getDataLayerData(sectionPos1); - if (dataLayer1 != null) { - lightUpdate = true; - synchronized (dataLayer1) { - byte[] bytes = dataLayer1.getData(); - Arrays.fill(bytes, (byte) 0); - } - } - } - } - - @Override - public CompoundTag getTile(int x, int y, int z) { - BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( - chunkX << 4), y, (z & 15) + ( - chunkZ << 4))); - if (blockEntity == null) { - return null; - } - return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)); - } - - @Override - public Map getTiles() { - Map nmsTiles = getChunk().getBlockEntities(); - if (nmsTiles.isEmpty()) { - return Collections.emptyMap(); - } - return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); - } - - @Override - public int getSkyLight(int x, int y, int z) { - int layer = y >> 4; - int alayer = layer - getMinSectionPosition(); - if (skyLight[alayer] == null) { - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = - serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.SKY).getDataLayerData(sectionPos); - // If the server hasn't generated the section's NibbleArray yet, it will be null - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. - Arrays.fill(LAYER_COUNT, (byte) 15); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( - LightLayer.BLOCK, - sectionPos, - dataLayer, - true - ); - } - skyLight[alayer] = dataLayer; - } - return skyLight[alayer].get(x & 15, y & 15, z & 15); - } - - @Override - public int getEmittedLight(int x, int y, int z) { - int layer = y >> 4; - int alayer = layer - getMinSectionPosition(); - if (blockLight[alayer] == null) { - serverLevel.getRawBrightness(new BlockPos(1, 1, 1), 5); - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = serverLevel - .getChunkSource() - .getLightEngine() - .getLayerListener(LightLayer.BLOCK) - .getDataLayerData(sectionPos); - // If the server hasn't generated the section's DataLayer yet, it will be null - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. - Arrays.fill(LAYER_COUNT, (byte) 15); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos, - dataLayer, true - ); - } - blockLight[alayer] = dataLayer; - } - return blockLight[alayer].get(x & 15, y & 15, z & 15); - } - - @Override - public int[] getHeightMap(HeightMapType type) { - long[] longArray = getChunk().heightmaps.get(Heightmap.Types.valueOf(type.name())).getRawData(); - BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256, longArray); - return bitArray.toRaw(new int[256]); - } - - @Override - public CompoundTag getEntity(UUID uuid) { - Entity entity = serverLevel.getEntity(uuid); - if (entity != null) { - org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); - return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); - } - for (CompoundTag tag : getEntities()) { - if (uuid.equals(tag.getUUID())) { - return tag; - } - } - return null; - } - - @Override - public Set getEntities() { - List entities = PaperweightPlatformAdapter.getEntities(getChunk()); - if (entities.isEmpty()) { - return Collections.emptySet(); - } - int size = entities.size(); - return new AbstractSet<>() { - @Override - public int size() { - return size; - } - - @Override - public boolean isEmpty() { - return false; - } - - @Override - public boolean contains(Object get) { - if (!(get instanceof CompoundTag getTag)) { - return false; - } - UUID getUUID = getTag.getUUID(); - for (Entity entity : entities) { - UUID uuid = entity.getUUID(); - if (uuid.equals(getUUID)) { - return true; - } - } - return false; - } - - @Nonnull - @Override - public Iterator iterator() { - Iterable result = entities.stream().map(input -> { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - input.save(tag); - return (CompoundTag) adapter.toNative(tag); - }).collect(Collectors.toList()); - return result.iterator(); - } - }; - } - - private void removeEntity(Entity entity) { - entity.discard(); - } - - public LevelChunk ensureLoaded(ServerLevel nmsWorld, int chunkX, int chunkZ) { - return PaperweightPlatformAdapter.ensureLoaded(nmsWorld, chunkX, chunkZ); - } - - @Override - @SuppressWarnings("rawtypes") - public synchronized > T call(IChunkSet set, Runnable finalizer) { - forceLoadSections = false; - copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; - try { - ServerLevel nmsWorld = serverLevel; - LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); - - // Remove existing tiles. Create a copy so that we can remove blocks - Map chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); - List beacons = null; - if (!chunkTiles.isEmpty()) { - for (Map.Entry entry : chunkTiles.entrySet()) { - final BlockPos pos = entry.getKey(); - final int lx = pos.getX() & 15; - final int ly = pos.getY(); - final int lz = pos.getZ() & 15; - final int layer = ly >> 4; - if (!set.hasSection(layer)) { - continue; - } - - int ordinal = set.getBlock(lx, ly, lz).getOrdinal(); - if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) { - BlockEntity tile = entry.getValue(); - if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) { - if (beacons == null) { - beacons = new ArrayList<>(); - } - beacons.add(tile); - PaperweightPlatformAdapter.removeBeacon(tile, nmsChunk); - continue; - } - nmsChunk.removeBlockEntity(tile.getBlockPos()); - if (createCopy) { - copy.storeTile(tile); - } - } - } - } - final BiomeType[][] biomes = set.getBiomes(); - - int bitMask = 0; - synchronized (nmsChunk) { - LevelChunkSection[] levelChunkSections = nmsChunk.getSections(); - - for (int layerNo = getMinSectionPosition(); layerNo <= getMaxSectionPosition(); layerNo++) { - - int getSectionIndex = layerNo - getMinSectionPosition(); - int setSectionIndex = layerNo - set.getMinSectionPosition(); - - if (!set.hasSection(layerNo)) { - // No blocks, but might be biomes present. Handle this lazily. - if (biomes == null) { - continue; - } - if (layerNo < set.getMinSectionPosition() || layerNo > set.getMaxSectionPosition()) { - continue; - } - if (biomes[setSectionIndex] != null) { - synchronized (super.sectionLocks[getSectionIndex]) { - LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; - if (createCopy && existingSection != null) { - copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); - } - - if (existingSection == null) { - PalettedContainer> biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer( - biomes[setSectionIndex], - biomeHolderIdMap - ); - LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection( - layerNo, - new char[4096], - adapter, - biomeRegistry, - biomeData - ); - if (PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - null, - newSection, - getSectionIndex - )) { - updateGet(nmsChunk, levelChunkSections, newSection, new char[4096], getSectionIndex); - continue; - } else { - existingSection = levelChunkSections[getSectionIndex]; - if (existingSection == null) { - LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - getSectionIndex - ); - continue; - } - } - } else { - setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); - } - } - } - continue; - } - - bitMask |= 1 << getSectionIndex; - - char[] setArr = set.load(layerNo); - - // synchronise on internal section to avoid circular locking with a continuing edit if the chunk was - // submitted to keep loaded internal chunks to queue target size. - synchronized (super.sectionLocks[getSectionIndex]) { - - LevelChunkSection newSection; - LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; - // Don't attempt to tick section whilst we're editing - if (existingSection != null) { - PaperweightPlatformAdapter.clearCounts(existingSection); - if (PaperLib.isPaper()) { - existingSection.tickingList.clear(); - } - } - - if (createCopy) { - char[] tmpLoad = loadPrivately(layerNo); - char[] copyArr = new char[4096]; - System.arraycopy(tmpLoad, 0, copyArr, 0, 4096); - copy.storeSection(getSectionIndex, copyArr); - if (biomes != null && existingSection != null) { - copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); - } - } - - if (existingSection == null) { - PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( - biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId( - BiomeTypes.PLAINS)), - PalettedContainer.Strategy.SECTION_BIOMES, - null - ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); - newSection = PaperweightPlatformAdapter.newChunkSection( - layerNo, - setArr, - adapter, - biomeRegistry, - biomeData - ); - if (PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - null, - newSection, - getSectionIndex - )) { - updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); - continue; - } else { - existingSection = levelChunkSections[getSectionIndex]; - if (existingSection == null) { - LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - getSectionIndex - ); - continue; - } - } - } - - //ensure that the server doesn't try to tick the chunksection while we're editing it. (Again) - PaperweightPlatformAdapter.clearCounts(existingSection); - if (PaperLib.isPaper()) { - existingSection.tickingList.clear(); - } - DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); - - // Synchronize to prevent further acquisitions - synchronized (lock) { - lock.acquire(); // Wait until we have the lock - lock.release(); - try { - sectionLock.writeLock().lock(); - if (this.getChunk() != nmsChunk) { - this.levelChunk = nmsChunk; - this.sections = null; - this.reset(); - } else if (existingSection != getSections(false)[getSectionIndex]) { - this.sections[getSectionIndex] = existingSection; - this.reset(); - } else if (!Arrays.equals( - update(getSectionIndex, new char[4096], true), - loadPrivately(layerNo) - )) { - this.reset(layerNo); - /*} else if (lock.isModified()) { - this.reset(layerNo);*/ - } - } finally { - sectionLock.writeLock().unlock(); - } - - PalettedContainer> biomeData = setBiomesToPalettedContainer( - biomes, - setSectionIndex, - existingSection.getBiomes() - ); - - newSection = - PaperweightPlatformAdapter.newChunkSection( - layerNo, - this::loadPrivately, - setArr, - adapter, - biomeRegistry, - biomeData - ); - if (!PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - existingSection, - newSection, - getSectionIndex - )) { - LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - getSectionIndex - ); - } else { - updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); - } - } - } - } - - Map heightMaps = set.getHeightMaps(); - for (Map.Entry entry : heightMaps.entrySet()) { - PaperweightGetBlocks.this.setHeightmapToGet(entry.getKey(), entry.getValue()); - } - PaperweightGetBlocks.this.setLightingToGet( - set.getLight(), - set.getMinSectionPosition(), - set.getMaxSectionPosition() - ); - PaperweightGetBlocks.this.setSkyLightingToGet( - set.getSkyLight(), - set.getMinSectionPosition(), - set.getMaxSectionPosition() - ); - - Runnable[] syncTasks = null; - - int bx = chunkX << 4; - int bz = chunkZ << 4; - - // Call beacon deactivate events here synchronously - // list will be null on spigot, so this is an implicit isPaper check - if (beacons != null && !beacons.isEmpty()) { - final List finalBeacons = beacons; - - syncTasks = new Runnable[4]; - - syncTasks[3] = () -> { - for (BlockEntity beacon : finalBeacons) { - BeaconBlockEntity.playSound(beacon.getLevel(), beacon.getBlockPos(), SoundEvents.BEACON_DEACTIVATE); - new BeaconDeactivatedEvent(CraftBlock.at(beacon.getLevel(), beacon.getBlockPos())).callEvent(); - } - }; - } - - Set entityRemoves = set.getEntityRemoves(); - if (entityRemoves != null && !entityRemoves.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[3]; - } - - syncTasks[2] = () -> { - Set entitiesRemoved = new HashSet<>(); - final List entities = PaperweightPlatformAdapter.getEntities(nmsChunk); - - for (Entity entity : entities) { - UUID uuid = entity.getUUID(); - if (entityRemoves.contains(uuid)) { - if (createCopy) { - copy.storeEntity(entity); - } - removeEntity(entity); - entitiesRemoved.add(uuid); - entityRemoves.remove(uuid); - } - } - if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { - for (UUID uuid : entityRemoves) { - Entity entity = nmsWorld.getEntities().get(uuid); - if (entity != null) { - removeEntity(entity); - } - } - } - // Only save entities that were actually removed to history - set.getEntityRemoves().clear(); - set.getEntityRemoves().addAll(entitiesRemoved); - }; - } - - Set entities = set.getEntities(); - if (entities != null && !entities.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[2]; - } - - syncTasks[1] = () -> { - Iterator iterator = entities.iterator(); - while (iterator.hasNext()) { - final CompoundTag nativeTag = iterator.next(); - final Map entityTagMap = nativeTag.getValue(); - final StringTag idTag = (StringTag) entityTagMap.get("Id"); - final ListTag posTag = (ListTag) entityTagMap.get("Pos"); - final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); - if (idTag == null || posTag == null || rotTag == null) { - LOGGER.error("Unknown entity tag: {}", nativeTag); - continue; - } - final double x = posTag.getDouble(0); - final double y = posTag.getDouble(1); - final double z = posTag.getDouble(2); - final float yaw = rotTag.getFloat(0); - final float pitch = rotTag.getFloat(1); - final String id = idTag.getValue(); - - EntityType type = EntityType.byString(id).orElse(null); - if (type != null) { - Entity entity = type.create(nmsWorld); - if (entity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); - for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - entity.load(tag); - entity.absMoveTo(x, y, z, yaw, pitch); - entity.setUUID(nativeTag.getUUID()); - if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { - LOGGER.warn( - "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", - id, - nmsWorld.getWorld().getName(), - x, - y, - z - ); - // Unsuccessful create should not be saved to history - iterator.remove(); - } - } - } - } - }; - } - - // set tiles - Map tiles = set.getTiles(); - if (tiles != null && !tiles.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[1]; - } - - syncTasks[0] = () -> { - for (final Map.Entry entry : tiles.entrySet()) { - final CompoundTag nativeTag = entry.getValue(); - final BlockVector3 blockHash = entry.getKey(); - final int x = blockHash.getX() + bx; - final int y = blockHash.getY(); - final int z = blockHash.getZ() + bz; - final BlockPos pos = new BlockPos(x, y, z); - - synchronized (nmsWorld) { - BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); - if (tileEntity == null || tileEntity.isRemoved()) { - nmsWorld.removeBlockEntity(pos); - tileEntity = nmsWorld.getBlockEntity(pos); - } - if (tileEntity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); - tag.put("x", IntTag.valueOf(x)); - tag.put("y", IntTag.valueOf(y)); - tag.put("z", IntTag.valueOf(z)); - tileEntity.load(tag); - } - } - } - }; - } - - Runnable callback; - if (bitMask == 0 && biomes == null && !lightUpdate) { - callback = null; - } else { - int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; - boolean finalLightUpdate = lightUpdate; - callback = () -> { - // Set Modified - nmsChunk.setLightCorrect(true); // Set Modified - nmsChunk.mustNotSave = false; - nmsChunk.setUnsaved(true); - // send to player - if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { - this.send(finalMask, finalLightUpdate); - } - if (finalizer != null) { - finalizer.run(); - } - }; - } - if (syncTasks != null) { - QueueHandler queueHandler = Fawe.instance().getQueueHandler(); - Runnable[] finalSyncTasks = syncTasks; - - // Chain the sync tasks and the callback - Callable chain = () -> { - try { - // Run the sync tasks - for (Runnable task : finalSyncTasks) { - if (task != null) { - task.run(); - } - } - if (callback == null) { - if (finalizer != null) { - finalizer.run(); - } - return null; - } else { - return queueHandler.async(callback, null); - } - } catch (Throwable e) { - e.printStackTrace(); - throw e; - } - }; - //noinspection unchecked - required at compile time - return (T) (Future) queueHandler.sync(chain); - } else { - if (callback == null) { - if (finalizer != null) { - finalizer.run(); - } - } else { - callback.run(); - } - } - } - return null; - } catch (Throwable e) { - e.printStackTrace(); - return null; - } finally { - forceLoadSections = true; - } - } - - private void updateGet( - LevelChunk nmsChunk, - LevelChunkSection[] chunkSections, - LevelChunkSection section, - char[] arr, - int layer - ) { - try { - sectionLock.writeLock().lock(); - if (this.getChunk() != nmsChunk) { - this.levelChunk = nmsChunk; - this.sections = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); - this.reset(); - } - if (this.sections == null) { - this.sections = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); - } - if (this.sections[layer] != section) { - // Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords - this.sections[layer] = new LevelChunkSection[]{section}.clone()[0]; - } - } finally { - sectionLock.writeLock().unlock(); - } - this.blocks[layer] = arr; - } - - private char[] loadPrivately(int layer) { - layer -= getMinSectionPosition(); - if (super.sections[layer] != null) { - synchronized (super.sectionLocks[layer]) { - if (super.sections[layer].isFull() && super.blocks[layer] != null) { - char[] blocks = new char[4096]; - System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096); - return blocks; - } - } - } - return PaperweightGetBlocks.this.update(layer, null, true); - } - - @Override - public synchronized void send(int mask, boolean lighting) { - PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); - } - - /** - * Update a given (nullable) data array to the current data stored in the server's chunk, associated with this - * {@link PaperweightPlatformAdapter} instance. Not synchronised to the {@link PaperweightPlatformAdapter} instance as synchronisation - * is handled where necessary in the method, and should otherwise be handled correctly by this method's caller. - * - * @param layer layer index (0 may denote a negative layer in the world, e.g. at y=-32) - * @param data array to be updated/filled with data or null - * @param aggressive if the cached section array should be re-acquired. - * @return the given array to be filled with data, or a new array if null is given. - */ - @Override - @SuppressWarnings("unchecked") - public char[] update(int layer, char[] data, boolean aggressive) { - LevelChunkSection section = getSections(aggressive)[layer]; - // Section is null, return empty array - if (section == null) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - return data; - } - if (data != null && data.length != 4096) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - } - if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - } - Semaphore lock = PaperweightPlatformAdapter.applyLock(section); - synchronized (lock) { - // Efficiently convert ChunkSection to raw data - try { - lock.acquire(); - - final PalettedContainer blocks = section.getStates(); - final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocks); - final BitStorage bits = (BitStorage) PaperweightPlatformAdapter.fieldStorage.get(dataObject); - - if (bits instanceof ZeroBitStorage) { - Arrays.fill(data, adapter.adaptToChar(blocks.get(0, 0, 0))); // get(int) is only public on paper - return data; - } - - final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get(dataObject); - - final int bitsPerEntry = bits.getBits(); - final long[] blockStates = bits.getRaw(); - - new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).toRaw(data); - - int num_palette; - if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { - num_palette = palette.getSize(); - } else { - // The section's palette is the global block palette. - for (int i = 0; i < 4096; i++) { - char paletteVal = data[i]; - char ordinal = adapter.ibdIDToOrdinal(paletteVal); - data[i] = ordinal; - } - return data; - } - - char[] paletteToOrdinal = FaweCache.INSTANCE.PALETTE_TO_BLOCK_CHAR.get(); - try { - if (num_palette != 1) { - for (int i = 0; i < num_palette; i++) { - char ordinal = ordinal(palette.valueFor(i), adapter); - paletteToOrdinal[i] = ordinal; - } - for (int i = 0; i < 4096; i++) { - char paletteVal = data[i]; - char val = paletteToOrdinal[paletteVal]; - if (val == Character.MAX_VALUE) { - val = ordinal(palette.valueFor(i), adapter); - paletteToOrdinal[i] = val; - } - data[i] = val; - } - } else { - char ordinal = ordinal(palette.valueFor(0), adapter); - Arrays.fill(data, ordinal); - } - } finally { - for (int i = 0; i < num_palette; i++) { - paletteToOrdinal[i] = Character.MAX_VALUE; - } - } - return data; - } catch (IllegalAccessException | InterruptedException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } finally { - lock.release(); - } - } - } - - private char ordinal(BlockState ibd, PaperweightFaweAdapter adapter) { - if (ibd == null) { - return BlockTypesCache.ReservedIDs.AIR; - } else { - return adapter.adaptToChar(ibd); - } - } - - public LevelChunkSection[] getSections(boolean force) { - force &= forceLoadSections; - sectionLock.readLock().lock(); - LevelChunkSection[] tmp = sections; - sectionLock.readLock().unlock(); - if (tmp == null || force) { - try { - sectionLock.writeLock().lock(); - tmp = sections; - if (tmp == null || force) { - LevelChunkSection[] chunkSections = getChunk().getSections(); - tmp = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length); - sections = tmp; - } - } finally { - sectionLock.writeLock().unlock(); - } - } - return tmp; - } - - public LevelChunk getChunk() { - LevelChunk levelChunk = this.levelChunk; - if (levelChunk == null) { - synchronized (this) { - levelChunk = this.levelChunk; - if (levelChunk == null) { - this.levelChunk = levelChunk = ensureLoaded(this.serverLevel, chunkX, chunkZ); - } - } - } - return levelChunk; - } - - private void fillLightNibble(char[][] light, LightLayer lightLayer, int minSectionPosition, int maxSectionPosition) { - for (int Y = 0; Y <= maxSectionPosition - minSectionPosition; Y++) { - if (light[Y] == null) { - continue; - } - SectionPos sectionPos = SectionPos.of(levelChunk.getPos(), Y + minSectionPosition); - DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(lightLayer).getDataLayerData( - sectionPos); - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - Arrays.fill(LAYER_COUNT, lightLayer == LightLayer.SKY ? (byte) 15 : (byte) 0); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( - lightLayer, - sectionPos, - dataLayer, - true - ); - } - synchronized (dataLayer) { - for (int x = 0; x < 16; x++) { - for (int y = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { - int i = y << 8 | z << 4 | x; - if (light[Y][i] < 16) { - dataLayer.set(x, y, z, light[Y][i]); - } - } - } - } - } - } - } - - private PalettedContainer> setBiomesToPalettedContainer( - final BiomeType[][] biomes, - final int sectionIndex, - final PalettedContainerRO> data - ) { - PalettedContainer> biomeData; - if (data instanceof PalettedContainer> palettedContainer) { - biomeData = palettedContainer; - } else { - LOGGER.warn( - "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + - "type {} but got {}", - PalettedContainer.class.getSimpleName(), - data.getClass().getSimpleName() - ); - biomeData = data.recreate(); - } - BiomeType[] sectionBiomes; - if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { - return biomeData; - } - for (int y = 0, index = 0; y < 4; y++) { - for (int z = 0; z < 4; z++) { - for (int x = 0; x < 4; x++, index++) { - BiomeType biomeType = sectionBiomes[index]; - if (biomeType == null) { - continue; - } - biomeData.set( - x, - y, - z, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId(biomeType)) - ); - } - } - } - return biomeData; - } - - @Override - public boolean hasSection(int layer) { - layer -= getMinSectionPosition(); - return getSections(false)[layer] != null; - } - - @Override - @SuppressWarnings("unchecked") - public synchronized boolean trim(boolean aggressive) { - skyLight = new DataLayer[getSectionCount()]; - blockLight = new DataLayer[getSectionCount()]; - if (aggressive) { - sectionLock.writeLock().lock(); - sections = null; - levelChunk = null; - sectionLock.writeLock().unlock(); - return super.trim(true); - } else if (sections == null) { - // don't bother trimming if there are no sections stored. - return true; - } else { - for (int i = getMinSectionPosition(); i <= getMaxSectionPosition(); i++) { - int layer = i - getMinSectionPosition(); - if (!hasSection(i) || !super.sections[layer].isFull()) { - continue; - } - LevelChunkSection existing = getSections(true)[layer]; - try { - final PalettedContainer blocksExisting = existing.getStates(); - - final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocksExisting); - final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get( - dataObject); - int paletteSize; - - if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { - paletteSize = palette.getSize(); - } else { - super.trim(false, i); - continue; - } - if (paletteSize == 1) { - //If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks. - continue; - } - super.trim(false, i); - } catch (IllegalAccessException ignored) { - super.trim(false, i); - } - } - return true; - } - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightGetBlocks_Copy.java deleted file mode 100644 index c0b69ac80..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightGetBlocks_Copy.java +++ /dev/null @@ -1,248 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1; - -import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; -import com.fastasyncworldedit.core.queue.IBlocks; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.math.BlockVector3; -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.BlockTypesCache; -import net.minecraft.core.Holder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import org.apache.logging.log4j.Logger; - -import javax.annotation.Nullable; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Future; - -public class PaperweightGetBlocks_Copy implements IChunkGet { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private final Map tiles = new HashMap<>(); - private final Set entities = new HashSet<>(); - private final char[][] blocks; - private final int minHeight; - private final int maxHeight; - final ServerLevel serverLevel; - final LevelChunk levelChunk; - private PalettedContainer>[] biomes = null; - - protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { - this.levelChunk = levelChunk; - this.serverLevel = levelChunk.level; - this.minHeight = serverLevel.getMinBuildHeight(); - this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. - this.blocks = new char[getSectionCount()][]; - } - - protected void storeTile(BlockEntity blockEntity) { - tiles.put( - BlockVector3.at( - blockEntity.getBlockPos().getX(), - blockEntity.getBlockPos().getY(), - blockEntity.getBlockPos().getZ() - ), - new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)) - ); - } - - @Override - public Map getTiles() { - return tiles; - } - - @Override - @Nullable - public CompoundTag getTile(int x, int y, int z) { - return tiles.get(BlockVector3.at(x, y, z)); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - protected void storeEntity(Entity entity) { - BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - entities.add((CompoundTag) adapter.toNative(compoundTag)); - } - - @Override - public Set getEntities() { - return this.entities; - } - - @Override - public CompoundTag getEntity(UUID uuid) { - for (CompoundTag tag : entities) { - if (uuid.equals(tag.getUUID())) { - return tag; - } - } - return null; - } - - @Override - public boolean isCreateCopy() { - return false; - } - - @Override - public void setCreateCopy(boolean createCopy) { - } - - @Override - public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { - } - - @Override - public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { - } - - @Override - public void setHeightmapToGet(HeightMapType type, int[] data) { - } - - @Override - public int getMaxY() { - return maxHeight; - } - - @Override - public int getMinY() { - return minHeight; - } - - @Override - public int getMaxSectionPosition() { - return maxHeight >> 4; - } - - @Override - public int getMinSectionPosition() { - return minHeight >> 4; - } - - @Override - public BiomeType getBiomeType(int x, int y, int z) { - Holder biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2); - return PaperweightPlatformAdapter.adapt(biome, serverLevel); - } - - @Override - public void removeSectionLighting(int layer, boolean sky) { - } - - @Override - public boolean trim(boolean aggressive, int layer) { - return false; - } - - @Override - public IBlocks reset() { - return null; - } - - @Override - public int getSectionCount() { - return serverLevel.getSectionsCount(); - } - - protected void storeSection(int layer, char[] data) { - blocks[layer] = data; - } - - protected void storeBiomes(int layer, PalettedContainerRO> biomeData) { - if (biomes == null) { - biomes = new PalettedContainer[getSectionCount()]; - } - if (biomeData instanceof PalettedContainer> palettedContainer) { - biomes[layer] = palettedContainer.copy(); - } else { - LOGGER.error( - "Cannot correctly save biomes to history. Expected class type {} but got {}", - PalettedContainer.class.getSimpleName(), - biomeData.getClass().getSimpleName() - ); - } - } - - @Override - public BaseBlock getFullBlock(int x, int y, int z) { - BlockState state = BlockTypesCache.states[get(x, y, z)]; - return state.toBaseBlock(this, x, y, z); - } - - @Override - public boolean hasSection(int layer) { - layer -= getMinSectionPosition(); - return blocks[layer] != null; - } - - @Override - public char[] load(int layer) { - layer -= getMinSectionPosition(); - return blocks[layer]; - } - - @Override - public char[] loadIfPresent(int layer) { - layer -= getMinSectionPosition(); - return blocks[layer]; - } - - @Override - public BlockState getBlock(int x, int y, int z) { - return BlockTypesCache.states[get(x, y, z)]; - } - - @Override - public int getSkyLight(int x, int y, int z) { - return 0; - } - - @Override - public int getEmittedLight(int x, int y, int z) { - return 0; - } - - @Override - public int[] getHeightMap(HeightMapType type) { - return new int[0]; - } - - @Override - public > T call(IChunkSet set, Runnable finalize) { - return null; - } - - public char get(int x, int y, int z) { - final int layer = (y >> 4) - getMinSectionPosition(); - final int index = (y & 15) << 8 | z << 4 | x; - return blocks[layer][index]; - } - - - @Override - public boolean trim(boolean aggressive) { - return false; - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightMapChunkUtil.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightMapChunkUtil.java deleted file mode 100644 index ead60b212..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightMapChunkUtil.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1; - -import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; - -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; - -//TODO un-very-break-this -public class PaperweightMapChunkUtil extends MapChunkUtil { - - public PaperweightMapChunkUtil() throws NoSuchFieldException { - fieldX = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("TWO_MEGABYTES", "a")); - fieldZ = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("x", "a")); - fieldBitMask = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("z", "b")); - fieldHeightMap = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("heightmaps", "b")); - fieldChunkData = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("chunkData", "c")); - fieldBlockEntities = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("buffer", "c")); - fieldFull = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("blockEntitiesData", "d")); - fieldX.setAccessible(true); - fieldZ.setAccessible(true); - fieldBitMask.setAccessible(true); - fieldHeightMap.setAccessible(true); - fieldChunkData.setAccessible(true); - fieldBlockEntities.setAccessible(true); - fieldFull.setAccessible(true); - } - - @Override - public ClientboundLevelChunkWithLightPacket createPacket() { - // TODO ??? return new ClientboundLevelChunkPacket(); - throw new UnsupportedOperationException(); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightPlatformAdapter.java deleted file mode 100644 index ae3d91027..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightPlatformAdapter.java +++ /dev/null @@ -1,703 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1; - -import com.destroystokyo.paper.util.maplist.EntityList; -import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; -import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; -import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.math.BitArrayUnstretched; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.ReflectionUtils; -import com.fastasyncworldedit.core.util.TaskManager; -import com.mojang.datafixers.util.Either; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -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.BlockTypesCache; -import io.papermc.lib.PaperLib; -import io.papermc.paper.world.ChunkEntitySlices; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.IdMap; -import net.minecraft.core.Registry; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.level.TicketType; -import net.minecraft.util.BitStorage; -import net.minecraft.util.ExceptionCollector; -import net.minecraft.util.SimpleBitStorage; -import net.minecraft.util.ThreadingDetector; -import net.minecraft.util.Unit; -import net.minecraft.util.ZeroBitStorage; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.EntityBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.GlobalPalette; -import net.minecraft.world.level.chunk.HashMapPalette; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.LinearPalette; -import net.minecraft.world.level.chunk.Palette; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.SingleValuePalette; -import net.minecraft.world.level.entity.PersistentEntitySectionManager; -import net.minecraft.world.level.gameevent.GameEventDispatcher; -import net.minecraft.world.level.gameevent.GameEventListener; -import org.bukkit.craftbukkit.v1_19_R1.CraftChunk; -import sun.misc.Unsafe; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Semaphore; -import java.util.function.Function; - -public final class PaperweightPlatformAdapter extends NMSAdapter { - - public static final Field fieldData; - - public static final Constructor dataConstructor; - - public static final Field fieldStorage; - public static final Field fieldPalette; - - private static final Field fieldTickingFluidCount; - private static final Field fieldTickingBlockCount; - private static final Field fieldNonEmptyBlockCount; - - private static final MethodHandle methodGetVisibleChunk; - - private static final int CHUNKSECTION_BASE; - private static final int CHUNKSECTION_SHIFT; - - private static final Field fieldThreadingDetector; - private static final long fieldThreadingDetectorOffset; - - private static final Field fieldLock; - private static final long fieldLockOffset; - - private static final MethodHandle methodRemoveGameEventListener; - private static final MethodHandle methodremoveTickingBlockEntity; - - private static final Field fieldRemove; - - static final boolean POST_CHUNK_REWRITE; - private static Method PAPER_CHUNK_GEN_ALL_ENTITIES; - private static Field LEVEL_CHUNK_ENTITIES; - private static Field SERVER_LEVEL_ENTITY_MANAGER; - - static { - try { - fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d")); - fieldData.setAccessible(true); - - Class dataClazz = fieldData.getType(); - dataConstructor = dataClazz.getDeclaredConstructors()[0]; - dataConstructor.setAccessible(true); - - fieldStorage = dataClazz.getDeclaredField(Refraction.pickName("storage", "b")); - fieldStorage.setAccessible(true); - fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c")); - fieldPalette.setAccessible(true); - - fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "h")); - fieldTickingFluidCount.setAccessible(true); - fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g")); - fieldTickingBlockCount.setAccessible(true); - fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f")); - fieldNonEmptyBlockCount.setAccessible(true); - - Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( - "getVisibleChunkIfPresent", - "b" - ), long.class); - getVisibleChunkIfPresent.setAccessible(true); - methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent); - - Unsafe unsafe = ReflectionUtils.getUnsafe(); - if (!PaperLib.isPaper()) { - fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); - fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector); - - fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); - fieldLockOffset = unsafe.objectFieldOffset(fieldLock); - } else { - // in paper, the used methods are synchronized properly - fieldThreadingDetector = null; - fieldThreadingDetectorOffset = -1; - - fieldLock = null; - fieldLockOffset = -1; - } - - Method removeGameEventListener = LevelChunk.class.getDeclaredMethod( - Refraction.pickName("removeGameEventListener", "a"), - BlockEntity.class, - ServerLevel.class - ); - removeGameEventListener.setAccessible(true); - methodRemoveGameEventListener = MethodHandles.lookup().unreflect(removeGameEventListener); - - Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod( - Refraction.pickName( - "removeBlockEntityTicker", - "l" - ), BlockPos.class - ); - removeBlockEntityTicker.setAccessible(true); - methodremoveTickingBlockEntity = MethodHandles.lookup().unreflect(removeBlockEntityTicker); - - fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p")); - fieldRemove.setAccessible(true); - - CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class); - int scale = unsafe.arrayIndexScale(LevelChunkSection[].class); - if ((scale & (scale - 1)) != 0) { - throw new Error("data type scale not a power of two"); - } - CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale); - boolean chunkRewrite; - try { - ServerLevel.class.getDeclaredMethod("getEntityLookup"); - chunkRewrite = true; - PAPER_CHUNK_GEN_ALL_ENTITIES = ChunkEntitySlices.class.getDeclaredMethod("getAllEntities"); - PAPER_CHUNK_GEN_ALL_ENTITIES.setAccessible(true); - } catch (NoSuchMethodException ignored) { - chunkRewrite = false; - } - try { - // Paper - Pre-Chunk-Update - LEVEL_CHUNK_ENTITIES = LevelChunk.class.getDeclaredField("entities"); - LEVEL_CHUNK_ENTITIES.setAccessible(true); - } catch (NoSuchFieldException ignored) { - } - try { - // Non-Paper - SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "P")); - SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true); - } catch (NoSuchFieldException ignored) { - } - POST_CHUNK_REWRITE = chunkRewrite; - } catch (RuntimeException e) { - throw e; - } catch (Throwable rethrow) { - rethrow.printStackTrace(); - throw new RuntimeException(rethrow); - } - } - - static boolean setSectionAtomic( - LevelChunkSection[] sections, - LevelChunkSection expected, - LevelChunkSection value, - int layer - ) { - long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE; - if (layer >= 0 && layer < sections.length) { - return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value); - } - return false; - } - - // There is no point in having a functional semaphore for paper servers. - private static final ThreadLocal SEMAPHORE_THREAD_LOCAL = - ThreadLocal.withInitial(() -> new DelegateSemaphore(1, null)); - - static DelegateSemaphore applyLock(LevelChunkSection section) { - if (PaperLib.isPaper()) { - return SEMAPHORE_THREAD_LOCAL.get(); - } - try { - synchronized (section) { - Unsafe unsafe = ReflectionUtils.getUnsafe(); - PalettedContainer blocks = section.getStates(); - ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject( - blocks, - fieldThreadingDetectorOffset - ); - synchronized (currentThreadingDetector) { - Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset); - if (currentLock instanceof DelegateSemaphore delegateSemaphore) { - return delegateSemaphore; - } - DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); - unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock); - return newLock; - } - } - } catch (Throwable e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - } - - public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) { - if (!PaperLib.isPaper()) { - LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false); - if (nmsChunk != null) { - return nmsChunk; - } - if (Fawe.isMainThread()) { - return serverLevel.getChunk(chunkX, chunkZ); - } - } else { - LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ); - if (nmsChunk != null) { - addTicket(serverLevel, chunkX, chunkZ); - return nmsChunk; - } - nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ); - if (nmsChunk != null) { - addTicket(serverLevel, chunkX, chunkZ); - return nmsChunk; - } - // Avoid "async" methods from the main thread. - if (Fawe.isMainThread()) { - return serverLevel.getChunk(chunkX, chunkZ); - } - CompletableFuture future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true); - try { - CraftChunk chunk = (CraftChunk) future.get(); - return chunk.getHandle(); - } catch (Throwable e) { - e.printStackTrace(); - } - } - return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)); - } - - private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) { - // Ensure chunk is definitely loaded before applying a ticket - io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel - .getChunkSource() - .addRegionTicket(TicketType.PLUGIN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE)); - } - - public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) { - ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap; - try { - return (ChunkHolder) methodGetVisibleChunk.invoke(chunkMap, ChunkPos.asLong(chunkX, chunkZ)); - } catch (Throwable thr) { - throw new RuntimeException(thr); - } - } - - @SuppressWarnings("deprecation") - public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) { - ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); - if (chunkHolder == null) { - return; - } - ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ); - LevelChunk levelChunk; - if (PaperLib.isPaper()) { - // getChunkAtIfLoadedImmediately is paper only - levelChunk = nmsWorld - .getChunkSource() - .getChunkAtIfLoadedImmediately(chunkX, chunkZ); - } else { - levelChunk = ((Optional) ((Either) chunkHolder - .getTickingChunkFuture() // method is not present with new paper chunk system - .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left()) - .orElse(null); - } - if (levelChunk == null) { - return; - } - TaskManager.taskManager().task(() -> { - ClientboundLevelChunkWithLightPacket packet; - if (PaperLib.isPaper()) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - true, - false // last false is to not bother with x-ray - ); - } else { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - true - ); - } - nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); - }); - } - - private static List nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) { - return serverLevel.getChunkSource().chunkMap.getPlayers(coordIntPair, false); - } - - /* - NMS conversion - */ - public static LevelChunkSection newChunkSection( - final int layer, - final char[] blocks, - CachedBukkitAdapter adapter, - Registry biomeRegistry, - @Nullable PalettedContainer> biomes - ) { - return newChunkSection(layer, null, blocks, adapter, biomeRegistry, biomes); - } - - public static LevelChunkSection newChunkSection( - final int layer, - final Function get, - char[] set, - CachedBukkitAdapter adapter, - Registry biomeRegistry, - @Nullable PalettedContainer> biomes - ) { - if (set == null) { - return newChunkSection(layer, biomeRegistry, biomes); - } - final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); - final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); - final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get(); - final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get(); - try { - int num_palette; - if (get == null) { - num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter, null); - } else { - num_palette = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, get, set, adapter, null); - } - - int bitsPerEntry = MathMan.log2nlz(num_palette - 1); - if (bitsPerEntry > 0 && bitsPerEntry < 5) { - bitsPerEntry = 4; - } else if (bitsPerEntry > 8) { - bitsPerEntry = MathMan.log2nlz(Block.BLOCK_STATE_REGISTRY.size() - 1); - } - - int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes - final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); - final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong); - - if (num_palette == 1) { - for (int i = 0; i < blockBitArrayEnd; i++) { - blockStates[i] = 0; - } - } else { - final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntryNonZero, 4096, blockStates); - bitArray.fromRaw(blocksCopy); - } - - final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd); - final BitStorage nmsBits; - if (bitsPerEntry == 0) { - nmsBits = new ZeroBitStorage(4096); - } else { - nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits); - } - List palette; - if (bitsPerEntry < 9) { - palette = new ArrayList<>(); - for (int i = 0; i < num_palette; i++) { - int ordinal = paletteToBlock[i]; - blockToPalette[ordinal] = Integer.MAX_VALUE; - final BlockState state = BlockTypesCache.states[ordinal]; - palette.add(((PaperweightBlockMaterial) state.getMaterial()).getState()); - } - } else { - palette = List.of(); - } - - // Create palette with data - @SuppressWarnings("deprecation") // constructor is deprecated on paper, but needed to keep compatibility with spigot - final PalettedContainer blockStatePalettedContainer = - new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, - PalettedContainer.Strategy.SECTION_STATES, - PalettedContainer.Strategy.SECTION_STATES.getConfiguration(Block.BLOCK_STATE_REGISTRY, bitsPerEntry), - nmsBits, - palette - ); - if (biomes == null) { - IdMap> biomeHolderIdMap = biomeRegistry.asHolderIdMap(); - biomes = new PalettedContainer<>( - biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId( - BiomeTypes.PLAINS)), - PalettedContainer.Strategy.SECTION_BIOMES, - null - ); - } - - return new LevelChunkSection(layer, blockStatePalettedContainer, biomes); - } catch (final Throwable e) { - throw e; - } finally { - Arrays.fill(blockToPalette, Integer.MAX_VALUE); - Arrays.fill(paletteToBlock, Integer.MAX_VALUE); - Arrays.fill(blockStates, 0); - Arrays.fill(blocksCopy, 0); - } - } - - @SuppressWarnings("deprecation") // Only deprecated in paper - private static LevelChunkSection newChunkSection( - int layer, - Registry biomeRegistry, - @Nullable PalettedContainer> biomes - ) { - if (biomes == null) { - return new LevelChunkSection(layer, biomeRegistry); - } - PalettedContainer dataPaletteBlocks = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, - Blocks.AIR.defaultBlockState(), - PalettedContainer.Strategy.SECTION_STATES, - null - ); - return new LevelChunkSection(layer, dataPaletteBlocks, biomes); - } - - /** - * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. - */ - public static PalettedContainer> getBiomePalettedContainer( - BiomeType[] biomes, - IdMap> biomeRegistry - ) { - if (biomes == null) { - return null; - } - BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); - // Don't stream this as typically will see 1-4 biomes; stream overhead is large for the small length - Map> palette = new HashMap<>(); - for (BiomeType biomeType : new LinkedList<>(Arrays.asList(biomes))) { - Holder biome; - if (biomeType == null) { - biome = biomeRegistry.byId(adapter.getInternalBiomeId(BiomeTypes.PLAINS)); - } else { - biome = biomeRegistry.byId(adapter.getInternalBiomeId(biomeType)); - } - palette.put(biomeType, biome); - } - int biomeCount = palette.size(); - int bitsPerEntry = MathMan.log2nlz(biomeCount - 1); - Object configuration = PalettedContainer.Strategy.SECTION_STATES.getConfiguration( - new FakeIdMapBiome(biomeCount), - bitsPerEntry - ); - if (bitsPerEntry > 3) { - bitsPerEntry = MathMan.log2nlz(biomeRegistry.size() - 1); - } - PalettedContainer> biomePalettedContainer = new PalettedContainer<>( - biomeRegistry, - biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), - PalettedContainer.Strategy.SECTION_BIOMES, - null - ); - - final Palette> biomePalette; - if (bitsPerEntry == 0) { - biomePalette = new SingleValuePalette<>( - biomePalettedContainer.registry, - biomePalettedContainer, - new ArrayList<>(palette.values()) // Must be modifiable - ); - } else if (bitsPerEntry == 4) { - biomePalette = LinearPalette.create( - 4, - biomePalettedContainer.registry, - biomePalettedContainer, - new ArrayList<>(palette.values()) // Must be modifiable - ); - } else if (bitsPerEntry < 9) { - biomePalette = HashMapPalette.create( - bitsPerEntry, - biomePalettedContainer.registry, - biomePalettedContainer, - new ArrayList<>(palette.values()) // Must be modifiable - ); - } else { - biomePalette = GlobalPalette.create( - bitsPerEntry, - biomePalettedContainer.registry, - biomePalettedContainer, - null // unused - ); - } - - int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes - final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); - final int arrayLength = MathMan.ceilZero(64f / blocksPerLong); - - - BitStorage bitStorage = bitsPerEntry == 0 ? new ZeroBitStorage(64) : new SimpleBitStorage( - bitsPerEntry, - 64, - new long[arrayLength] - ); - - try { - Object data = dataConstructor.newInstance(configuration, bitStorage, biomePalette); - fieldData.set(biomePalettedContainer, data); - int index = 0; - for (int y = 0; y < 4; y++) { - for (int z = 0; z < 4; z++) { - for (int x = 0; x < 4; x++, index++) { - BiomeType biomeType = biomes[index]; - if (biomeType == null) { - continue; - } - Holder biome = biomeRegistry.byId(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId(biomeType)); - if (biome == null) { - continue; - } - biomePalettedContainer.set(x, y, z, biome); - } - } - } - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException(e); - } - return biomePalettedContainer; - } - - public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException { - fieldTickingFluidCount.setShort(section, (short) 0); - fieldTickingBlockCount.setShort(section, (short) 0); - } - - public static BiomeType adapt(Holder biome, LevelAccessor levelAccessor) { - final Registry biomeRegistry = levelAccessor.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY); - if (biomeRegistry.getKey(biome.value()) == null) { - return biomeRegistry.asHolderIdMap().getId(biome) == -1 ? BiomeTypes.OCEAN - : null; - } - return BiomeTypes.get(biome.unwrapKey().orElseThrow().location().toString()); - } - - static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { - try { - if (levelChunk.loaded || levelChunk.level.isClientSide()) { - BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos()); - if (blockEntity != null) { - if (!levelChunk.level.isClientSide) { - methodRemoveGameEventListener.invoke(levelChunk, beacon, levelChunk.level); - } - fieldRemove.set(beacon, true); - } - } - methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos()); - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - } - - static List getEntities(LevelChunk chunk) { - ExceptionCollector collector = new ExceptionCollector<>(); - if (PaperLib.isPaper()) { - if (POST_CHUNK_REWRITE) { - try { - //noinspection unchecked - return (List) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level.getEntityLookup().getChunk(chunk.locX, chunk.locZ)); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=true]", e); - } - } - try { - EntityList entityList = (EntityList) LEVEL_CHUNK_ENTITIES.get(chunk); - return List.of(entityList.getRawData()); - } catch (IllegalAccessException e) { - collector.add(new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=false]", e)); - // fall through - } - } - try { - //noinspection unchecked - return ((PersistentEntitySectionManager) (SERVER_LEVEL_ENTITY_MANAGER.get(chunk.level))).getEntities(chunk.getPos()); - } catch (IllegalAccessException e) { - collector.add(new RuntimeException("Failed to lookup entities [PAPER=false]", e)); - } - collector.throwIfPresent(); - return List.of(); - } - - record FakeIdMapBlock(int size) implements IdMap { - - @Override - public int getId(final net.minecraft.world.level.block.state.BlockState entry) { - return 0; - } - - @Nullable - @Override - public net.minecraft.world.level.block.state.BlockState byId(final int index) { - return null; - } - - @Nonnull - @Override - public Iterator iterator() { - return Collections.emptyIterator(); - } - - } - - record FakeIdMapBiome(int size) implements IdMap { - - @Override - public int getId(final Biome entry) { - return 0; - } - - @Nullable - @Override - public Biome byId(final int index) { - return null; - } - - @Nonnull - @Override - public Iterator iterator() { - return Collections.emptyIterator(); - } - - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightPostProcessor.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightPostProcessor.java deleted file mode 100644 index 4bbf3baca..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightPostProcessor.java +++ /dev/null @@ -1,175 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1; - -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.ProcessorScope; -import com.fastasyncworldedit.core.queue.IBatchProcessor; -import com.fastasyncworldedit.core.queue.IChunk; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.fastasyncworldedit.core.registry.state.PropertyKey; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.Fluids; - -import javax.annotation.Nullable; - -public class PaperweightPostProcessor implements IBatchProcessor { - - @Override - public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) { - return set; - } - - @SuppressWarnings("deprecation") - @Override - public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) { - boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS; - // The PostProcessor shouldn't be added, but just in case - if (!tickFluid) { - return; - } - PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet; - layer: - for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) { - char[] set = iChunkSet.loadIfPresent(layer); - if (set == null) { - // No edit means no need to process - continue; - } - char[] get = null; - for (int i = 0; i < 4096; i++) { - char ordinal = set[i]; - char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__; - boolean fromGet = false; // Used for liquids - if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { - if (get == null) { - get = getBlocks.load(layer); - } - // If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't - // actually being set - if (get == null) { - continue layer; - } - fromGet = true; - ordinal = replacedOrdinal = get[i]; - } - if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { - continue; - } else if (!fromGet) { // if fromGet, don't do the same again - if (get == null) { - get = getBlocks.load(layer); - } - replacedOrdinal = get[i]; - } - boolean ticking = BlockTypesCache.ticking[ordinal]; - boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal]; - boolean replacedWasLiquid = false; - BlockState replacedState = null; - if (!ticking) { - // If the block being replaced was not ticking, it cannot be a liquid - if (!replacedWasTicking) { - continue; - } - // If the block being replaced is not fluid, we do not need to worry - if (!(replacedWasLiquid = - (replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) { - continue; - } - } - BlockState state = BlockState.getFromOrdinal(ordinal); - boolean liquid = state.getMaterial().isLiquid(); - int x = i & 15; - int y = (i >> 8) & 15; - int z = (i >> 4) & 15; - BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z); - if (liquid || replacedWasLiquid) { - if (liquid) { - addFluid(getBlocks.serverLevel, state, position); - continue; - } - // If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this - // may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up - // being ticked anyway. We only need it to be "hit" once. - if (!wasAdjacentToWater(get, set, i, x, y, z)) { - continue; - } - addFluid(getBlocks.serverLevel, replacedState, position); - } - } - } - } - - @Nullable - @Override - public Extent construct(final Extent child) { - throw new UnsupportedOperationException("Processing only"); - } - - @Override - public ProcessorScope getScope() { - return ProcessorScope.READING_SET_BLOCKS; - } - - private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) { - if (set == null || get == null) { - return false; - } - char ordinal; - char reserved = BlockTypesCache.ReservedIDs.__RESERVED__; - if (x > 0 && set[i - 1] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) { - return true; - } - } - if (x < 15 && set[i + 1] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) { - return true; - } - } - if (z > 0 && set[i - 16] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) { - return true; - } - } - if (z < 15 && set[i + 16] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) { - return true; - } - } - if (y > 0 && set[i - 256] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) { - return true; - } - } - if (y < 15 && set[i + 256] != reserved) { - return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal); - } - return false; - } - - @SuppressWarnings("deprecation") - private boolean isFluid(char ordinal) { - return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid(); - } - - @SuppressWarnings("deprecation") - private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) { - Fluid type; - if (replacedState.getBlockType() == BlockTypes.LAVA) { - type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA; - } else { - type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER; - } - serverLevel.scheduleTick( - position, - type, - type.getTickDelay(serverLevel) - ); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightStarlightRelighter.java deleted file mode 100644 index 8e1e763b1..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightStarlightRelighter.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1; - -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter; -import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; -import com.fastasyncworldedit.core.queue.IQueueChunk; -import com.fastasyncworldedit.core.queue.IQueueExtent; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.TaskManager; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -import it.unimi.dsi.fastutil.longs.LongArraySet; -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.longs.LongSet; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.TicketType; -import net.minecraft.util.Unit; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.chunk.ChunkStatus; -import org.apache.logging.log4j.Logger; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Consumer; -import java.util.function.IntConsumer; - -public class PaperweightStarlightRelighter implements Relighter { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - private static final int CHUNKS_PER_BATCH = 1024; // 32 * 32 - private static final int CHUNKS_PER_BATCH_SQRT_LOG2 = 5; // for shifting - - private static final TicketType FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); - private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkStatus.getDistance(ChunkStatus.LIGHT); - - - private final ServerLevel serverLevel; - private final ReentrantLock lock = new ReentrantLock(); - private final Long2ObjectLinkedOpenHashMap regions = new Long2ObjectLinkedOpenHashMap<>(); - private final ReentrantLock areaLock = new ReentrantLock(); - private final NMSRelighter delegate; - - @SuppressWarnings("rawtypes") - public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { - this.serverLevel = serverLevel; - this.delegate = new NMSRelighter(queue); - } - - @Override - public boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask) { - areaLock.lock(); - try { - long key = MathMan.pairInt(cx >> CHUNKS_PER_BATCH_SQRT_LOG2, cz >> CHUNKS_PER_BATCH_SQRT_LOG2); - // TODO probably submit here already if chunks.size == CHUNKS_PER_BATCH? - LongSet chunks = this.regions.computeIfAbsent(key, k -> new LongArraySet(CHUNKS_PER_BATCH >> 2)); - chunks.add(ChunkPos.asLong(cx, cz)); - } finally { - areaLock.unlock(); - } - return true; - } - - @Override - public void addLightUpdate(int x, int y, int z) { - delegate.addLightUpdate(x, y, z); - } - - /* - * This method is called "recursively", iterating and removing elements - * from the regions linked map. This way, chunks are loaded in batches to avoid - * OOMEs. - */ - @Override - public void fixLightingSafe(boolean sky) { - this.areaLock.lock(); - try { - if (regions.isEmpty()) { - return; - } - LongSet first = regions.removeFirst(); - fixLighting(first, () -> fixLightingSafe(true)); - } finally { - this.areaLock.unlock(); - } - } - - /* - * Processes a set of chunks and runs an action afterwards. - * The action is run async, the chunks are partly processed on the main thread - * (as required by the server). - */ - private void fixLighting(LongSet chunks, Runnable andThen) { - // convert from long keys to ChunkPos - Set coords = new HashSet<>(); - LongIterator iterator = chunks.iterator(); - while (iterator.hasNext()) { - coords.add(new ChunkPos(iterator.nextLong())); - } - TaskManager.taskManager().task(() -> { - // trigger chunk load and apply ticket on main thread - List> futures = new ArrayList<>(); - for (ChunkPos pos : coords) { - futures.add(serverLevel.getWorld().getChunkAtAsync(pos.x, pos.z) - .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( - FAWE_TICKET, - pos, - LIGHT_LEVEL, - Unit.INSTANCE - )) - ); - } - // collect futures and trigger relight once all chunks are loaded - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(v -> - invokeRelight( - coords, - c -> { - }, // no callback for single chunks required - i -> { - if (i != coords.size()) { - LOGGER.warn("Processed {} chunks instead of {}", i, coords.size()); - } - // post process chunks on main thread - TaskManager.taskManager().task(() -> postProcessChunks(coords)); - // call callback on our own threads - TaskManager.taskManager().async(andThen); - } - ) - ); - }); - } - - private void invokeRelight( - Set coords, - Consumer chunkCallback, - IntConsumer processCallback - ) { - try { - serverLevel.getChunkSource().getLightEngine().relight(coords, chunkCallback, processCallback); - } catch (Exception e) { - LOGGER.error("Error occurred on relighting", e); - } - } - - /* - * Allow the server to unload the chunks again. - * Also, if chunk packets are sent delayed, we need to do that here - */ - private void postProcessChunks(Set coords) { - boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING; - for (ChunkPos pos : coords) { - int x = pos.x; - int z = pos.z; - if (delay) { // we still need to send the block changes of that chunk - PaperweightPlatformAdapter.sendChunk(serverLevel, x, z, false); - } - serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE); - } - } - - @Override - public void clear() { - - } - - @Override - public void removeLighting() { - this.delegate.removeLighting(); - } - - @Override - public void fixBlockLighting() { - fixLightingSafe(true); - } - - @Override - public void fixSkyLighting() { - fixLightingSafe(true); - } - - @Override - public boolean isEmpty() { - return true; - } - - @Override - public ReentrantLock getLock() { - return this.lock; - } - - @Override - public boolean isFinished() { - return false; - } - - @Override - public void close() throws Exception { - fixLightingSafe(true); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightStarlightRelighterFactory.java deleted file mode 100644 index d7ff69151..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/PaperweightStarlightRelighterFactory.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1; - -import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; -import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; -import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; -import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IQueueChunk; -import com.fastasyncworldedit.core.queue.IQueueExtent; -import com.sk89q.worldedit.world.World; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; - -import javax.annotation.Nonnull; - -public class PaperweightStarlightRelighterFactory implements RelighterFactory { - - @Override - public @Nonnull - @SuppressWarnings("rawtypes") - Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { - org.bukkit.World w = Bukkit.getWorld(world.getName()); - if (w == null) { - return NullRelighter.INSTANCE; - } - return new PaperweightStarlightRelighter(((CraftWorld) w).getHandle(), queue); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/nbt/PaperweightLazyCompoundTag.java deleted file mode 100644 index ff9b73642..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/nbt/PaperweightLazyCompoundTag.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1.nbt; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.LazyCompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import net.minecraft.nbt.NumericTag; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Supplier; - -public class PaperweightLazyCompoundTag extends LazyCompoundTag { - - private final Supplier compoundTagSupplier; - private CompoundTag compoundTag; - - public PaperweightLazyCompoundTag(Supplier compoundTagSupplier) { - super(new HashMap<>()); - this.compoundTagSupplier = compoundTagSupplier; - } - - public PaperweightLazyCompoundTag(net.minecraft.nbt.CompoundTag compoundTag) { - this(() -> compoundTag); - } - - public net.minecraft.nbt.CompoundTag get() { - return compoundTagSupplier.get(); - } - - @Override - @SuppressWarnings("unchecked") - public Map getValue() { - if (compoundTag == null) { - compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); - } - return compoundTag.getValue(); - } - - @Override - public CompoundBinaryTag asBinaryTag() { - getValue(); - return compoundTag.asBinaryTag(); - } - - public boolean containsKey(String key) { - return compoundTagSupplier.get().contains(key); - } - - public byte[] getByteArray(String key) { - return compoundTagSupplier.get().getByteArray(key); - } - - public byte getByte(String key) { - return compoundTagSupplier.get().getByte(key); - } - - public double getDouble(String key) { - return compoundTagSupplier.get().getDouble(key); - } - - public double asDouble(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsDouble(); - } - return 0; - } - - public float getFloat(String key) { - return compoundTagSupplier.get().getFloat(key); - } - - public int[] getIntArray(String key) { - return compoundTagSupplier.get().getIntArray(key); - } - - public int getInt(String key) { - return compoundTagSupplier.get().getInt(key); - } - - public int asInt(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsInt(); - } - return 0; - } - - @SuppressWarnings("unchecked") - public List getList(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof net.minecraft.nbt.ListTag nbtList) { - ArrayList list = new ArrayList<>(); - for (net.minecraft.nbt.Tag elem : nbtList) { - if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { - list.add(new PaperweightLazyCompoundTag(compoundTag)); - } else { - list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem)); - } - } - return list; - } - return Collections.emptyList(); - } - - @SuppressWarnings("unchecked") - public ListTag getListTag(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof net.minecraft.nbt.ListTag) { - return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag); - } - return new ListTag(StringTag.class, Collections.emptyList()); - } - - @SuppressWarnings("unchecked") - public List getList(String key, Class listType) { - ListTag listTag = getListTag(key); - if (listTag.getType().equals(listType)) { - return (List) listTag.getValue(); - } else { - return Collections.emptyList(); - } - } - - public long[] getLongArray(String key) { - return compoundTagSupplier.get().getLongArray(key); - } - - public long getLong(String key) { - return compoundTagSupplier.get().getLong(key); - } - - public long asLong(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsLong(); - } - return 0; - } - - public short getShort(String key) { - return compoundTagSupplier.get().getShort(key); - } - - public String getString(String key) { - return compoundTagSupplier.get().getString(key); - } - - @Override - public String toString() { - return compoundTagSupplier.get().toString(); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/regen/PaperweightRegen.java deleted file mode 100644 index ebe096996..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R1/regen/PaperweightRegen.java +++ /dev/null @@ -1,564 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1.regen; - -import com.fastasyncworldedit.bukkit.adapter.Regenerator; -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.queue.IChunkCache; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.util.ReflectionUtils; -import com.fastasyncworldedit.core.util.TaskManager; -import com.google.common.collect.ImmutableList; -import com.mojang.datafixers.util.Either; -import com.mojang.serialization.Lifecycle; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1.PaperweightGetBlocks; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.world.RegenOptions; -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.data.BuiltinRegistries; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.server.level.progress.ChunkProgressListener; -import net.minecraft.util.thread.ProcessorHandle; -import net.minecraft.util.thread.ProcessorMailbox; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.LevelSettings; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.BiomeSource; -import net.minecraft.world.level.biome.FixedBiomeSource; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkGenerator; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.FlatLevelSource; -import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; -import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; -import net.minecraft.world.level.levelgen.WorldGenSettings; -import net.minecraft.world.level.levelgen.blending.BlendingData; -import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; -import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; -import net.minecraft.world.level.storage.LevelStorageSource; -import net.minecraft.world.level.storage.PrimaryLevelData; -import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_19_R1.CraftServer; -import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R1.generator.CustomChunkGenerator; -import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; - -import javax.annotation.Nullable; -import java.io.IOException; -import java.lang.reflect.Field; -import java.nio.file.Path; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.OptionalLong; -import java.util.Random; -import java.util.concurrent.CompletableFuture; -import java.util.function.BooleanSupplier; -import java.util.function.Supplier; - -public class PaperweightRegen extends Regenerator { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private static final Field serverWorldsField; - private static final Field paperConfigField; - private static final Field flatBedrockField; - private static final Field generatorSettingFlatField; - private static final Field generatorSettingBaseSupplierField; - private static final Field delegateField; - private static final Field chunkSourceField; - private static final Field ringPositionsField; - private static final Field hasGeneratedPositionsField; - - //list of chunk stati in correct order without FULL - private static final Map chunkStati = new LinkedHashMap<>(); - - static { - chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing - chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps - chunkStati.put( - ChunkStatus.STRUCTURE_REFERENCES, - Concurrency.FULL - ); // structure refs: radius 8, but only writes to current chunk - chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // biomes: radius 0 - chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8 - chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE - chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results - chunkStati.put( - ChunkStatus.LIQUID_CARVERS, - Concurrency.NONE - ); // liquid carvers: radius 0, but RADIUS and FULL change results - chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps - chunkStati.put( - ChunkStatus.LIGHT, - Concurrency.FULL - ); // light: radius 1, but no writes to other chunks, only current chunk - chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0 - chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0 - - try { - serverWorldsField = CraftServer.class.getDeclaredField("worlds"); - serverWorldsField.setAccessible(true); - - Field tmpPaperConfigField; - Field tmpFlatBedrockField; - try { //only present on paper - tmpPaperConfigField = Level.class.getDeclaredField("paperConfig"); - tmpPaperConfigField.setAccessible(true); - - tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock"); - tmpFlatBedrockField.setAccessible(true); - } catch (Exception e) { - tmpPaperConfigField = null; - tmpFlatBedrockField = null; - } - paperConfigField = tmpPaperConfigField; - flatBedrockField = tmpFlatBedrockField; - - generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName( - "settings", "g")); - generatorSettingBaseSupplierField.setAccessible(true); - - generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "f")); - generatorSettingFlatField.setAccessible(true); - - delegateField = CustomChunkGenerator.class.getDeclaredField("delegate"); - delegateField.setAccessible(true); - - chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "L")); - chunkSourceField.setAccessible(true); - - ringPositionsField = ChunkGenerator.class.getDeclaredField(Refraction.pickName("ringPositions", "i")); - ringPositionsField.setAccessible(true); - - hasGeneratedPositionsField = ChunkGenerator.class.getDeclaredField(Refraction.pickName("hasGeneratedPositions", "j")); - hasGeneratedPositionsField.setAccessible(true); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - //runtime - private ServerLevel originalServerWorld; - private ServerChunkCache originalChunkProvider; - private ServerLevel freshWorld; - private ServerChunkCache freshChunkProvider; - private LevelStorageSource.LevelStorageAccess session; - private StructureTemplateManager structureTemplateManager; - private ThreadedLevelLightEngine threadedLevelLightEngine; - private ChunkGenerator chunkGenerator; - - private Path tempDir; - - private boolean generateFlatBedrock = false; - - public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) { - super(originalBukkitWorld, region, target, options); - } - - @Override - protected boolean prepare() { - this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle(); - originalChunkProvider = originalServerWorld.getChunkSource(); - if (!(originalChunkProvider instanceof ServerChunkCache)) { - return false; - } - - //flat bedrock? (only on paper) - if (paperConfigField != null) { - try { - generateFlatBedrock = flatBedrockField.getBoolean(paperConfigField.get(originalServerWorld)); - } catch (Exception ignored) { - } - } - - seed = options.getSeed().orElse(originalServerWorld.getSeed()); - chunkStati.forEach((s, c) -> super.chunkStati.put(new ChunkStatusWrap(s), c)); - - return true; - } - - @Override - @SuppressWarnings("unchecked") - protected boolean initNewWorld() throws Exception { - //world folder - tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen"); - - //prepare for world init (see upstream implementation for reference) - org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment(); - org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator(); - LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir); - ResourceKey levelStemResourceKey = getWorldDimKey(environment); - session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey); - PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData; - - MinecraftServer server = originalServerWorld.getCraftServer().getServer(); - WorldGenSettings originalOpts = originalWorldData.worldGenSettings(); - WorldGenSettings newOpts = options.getSeed().isPresent() - ? originalOpts.withSeed(originalWorldData.isHardcore(), OptionalLong.of(seed)) - : originalOpts; - LevelSettings newWorldSettings = new LevelSettings( - "faweregentempworld", - originalWorldData.settings.gameType(), - originalWorldData.settings.hardcore(), - originalWorldData.settings.difficulty(), - originalWorldData.settings.allowCommands(), - originalWorldData.settings.gameRules(), - originalWorldData.settings.getDataPackConfig() - ); - PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, Lifecycle.stable()); - - BiomeProvider biomeProvider = getBiomeProvider(); - - //init world - freshWorld = Fawe.instance().getQueueHandler().sync((Supplier) () -> new ServerLevel( - server, - server.executor, - session, - newWorldData, - originalServerWorld.dimension(), - newOpts.dimensions().getOrThrow(levelStemResourceKey), - new RegenNoOpWorldLoadListener(), - originalServerWorld.isDebug(), - seed, - ImmutableList.of(), - false, - environment, - generator, - biomeProvider - ) { - private final Holder singleBiome = options.hasBiomeType() ? BuiltinRegistries.BIOME.asHolderIdMap().byId( - WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) - ) : null; - - @Override - public void tick(BooleanSupplier shouldKeepTicking) { //no ticking - } - - @Override - public Holder getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { - if (options.hasBiomeType()) { - return singleBiome; - } - return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome( - biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler() - ); - } - }).get(); - freshWorld.noSave = true; - removeWorldFromWorldsMap(); - newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name - if (paperConfigField != null) { - paperConfigField.set(freshWorld, originalServerWorld.paperConfig()); - } - - ChunkGenerator originalGenerator = originalChunkProvider.getGenerator(); - if (originalGenerator instanceof FlatLevelSource flatLevelSource) { - FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings(); - chunkGenerator = new FlatLevelSource(originalGenerator.structureSets, generatorSettingFlat); - } else if (originalGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) { - Holder generatorSettingBaseSupplier = (Holder) generatorSettingBaseSupplierField.get( - originalGenerator); - BiomeSource biomeSource; - if (options.hasBiomeType()) { - biomeSource = new FixedBiomeSource(BuiltinRegistries.BIOME - .asHolderIdMap() - .byId(WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()))); - } else { - biomeSource = originalGenerator.getBiomeSource(); - } - chunkGenerator = new NoiseBasedChunkGenerator(originalGenerator.structureSets, - noiseBasedChunkGenerator.noises, - biomeSource, - generatorSettingBaseSupplier - ); - } else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) { - chunkGenerator = customChunkGenerator.getDelegate(); - } else { - LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName()); - return false; - } - if (generator != null) { - chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator); - generateConcurrent = generator.isParallelCapable(); - } - chunkGenerator.conf = freshWorld.spigotConfig; - - if (seed == originalOpts.seed() && !options.hasBiomeType()) { - // Optimisation for needless ring position calculation when the seed and biome is the same. - boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(originalGenerator); - if (hasGeneratedPositions) { - Map>> ringPositions = - (Map>>) ringPositionsField.get( - originalGenerator); - Map>> copy = new Object2ObjectArrayMap<>(ringPositions); - ringPositionsField.set(chunkGenerator, copy); - hasGeneratedPositionsField.setBoolean(chunkGenerator, true); - } - } - - freshChunkProvider = new ServerChunkCache( - freshWorld, - session, - server.getFixerUpper(), - server.getStructureManager(), - server.executor, - chunkGenerator, - freshWorld.spigotConfig.viewDistance, - freshWorld.spigotConfig.simulationDistance, - server.forceSynchronousWrites(), - new RegenNoOpWorldLoadListener(), - (chunkCoordIntPair, state) -> { - }, - () -> server.overworld().getDataStorage() - ) { - // redirect to LevelChunks created in #createChunks - @Override - public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean create) { - ChunkAccess chunkAccess = getChunkAt(x, z); - if (chunkAccess == null && create) { - chunkAccess = createChunk(getProtoChunkAt(x, z)); - } - return chunkAccess; - } - }; - - ReflectionUtils.unsafeSet(chunkSourceField, freshWorld, freshChunkProvider); - //let's start then - structureTemplateManager = server.getStructureManager(); - threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider); - - return true; - } - - @Override - protected void cleanup() { - try { - session.close(); - } catch (Exception ignored) { - } - - //shutdown chunk provider - try { - Fawe.instance().getQueueHandler().sync(() -> { - try { - freshChunkProvider.close(false); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - } catch (Exception ignored) { - } - - //remove world from server - try { - Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap); - } catch (Exception ignored) { - } - - //delete directory - try { - SafeFiles.tryHardToDeleteDir(tempDir); - } catch (Exception ignored) { - } - } - - @Override - protected ProtoChunk createProtoChunk(int x, int z) { - return new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld, - this.freshWorld.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null - ); - } - - @Override - protected LevelChunk createChunk(ProtoChunk protoChunk) { - return new LevelChunk( - freshWorld, - protoChunk, - null // we don't want to add entities - ); - } - - @Override - protected ChunkStatusWrap getFullChunkStatus() { - return new ChunkStatusWrap(ChunkStatus.FULL); - } - - @Override - protected List getBlockPopulators() { - return originalServerWorld.getWorld().getPopulators(); - } - - @Override - protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) { - // BlockPopulator#populate has to be called synchronously for TileEntity access - TaskManager.taskManager().task(() -> blockPopulator.populate(freshWorld.getWorld(), random, levelChunk.getBukkitChunk())); - } - - @Override - protected IChunkCache initSourceQueueCache() { - return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) { - @Override - public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) { - return getChunkAt(x, z); - } - }; - } - - //util - @SuppressWarnings("unchecked") - private void removeWorldFromWorldsMap() { - Fawe.instance().getQueueHandler().sync(() -> { - try { - Map map = (Map) serverWorldsField.get(Bukkit.getServer()); - map.remove("faweregentempworld"); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - }); - } - - private ResourceKey getWorldDimKey(org.bukkit.World.Environment env) { - return switch (env) { - case NETHER -> LevelStem.NETHER; - case THE_END -> LevelStem.END; - default -> LevelStem.OVERWORLD; - }; - } - - private static class RegenNoOpWorldLoadListener implements ChunkProgressListener { - - private RegenNoOpWorldLoadListener() { - } - - @Override - public void updateSpawnPos(ChunkPos spawnPos) { - } - - @Override - public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) { - } - - @Override - public void start() { - - } - - @Override - public void stop() { - } - - // TODO Paper only(?) @Override - public void setChunkRadius(int radius) { - } - - } - - private class FastProtoChunk extends ProtoChunk { - - public FastProtoChunk( - final ChunkPos pos, - final UpgradeData upgradeData, - final LevelHeightAccessor world, - final Registry biomeRegistry, - @Nullable final BlendingData blendingData - ) { - super(pos, upgradeData, world, biomeRegistry, blendingData); - } - - // avoid warning on paper - - // compatibility with spigot - - public boolean generateFlatBedrock() { - return generateFlatBedrock; - } - - // no one will ever see the entities! - @Override - public List getEntities() { - return Collections.emptyList(); - } - - } - - protected class ChunkStatusWrap extends ChunkStatusWrapper { - - private final ChunkStatus chunkStatus; - - public ChunkStatusWrap(ChunkStatus chunkStatus) { - this.chunkStatus = chunkStatus; - } - - @Override - public int requiredNeighborChunkRadius() { - return chunkStatus.getRange(); - } - - @Override - public String name() { - return chunkStatus.getName(); - } - - @Override - public CompletableFuture processChunk(Long xz, List accessibleChunks) { - return chunkStatus.generate( - Runnable::run, // TODO revisit, we might profit from this somehow? - freshWorld, - chunkGenerator, - structureTemplateManager, - threadedLevelLightEngine, - c -> CompletableFuture.completedFuture(Either.left(c)), - accessibleChunks, - true - ); - } - - } - - /** - * A light engine that does nothing. As light is calculated after pasting anyway, we can avoid - * work this way. - */ - static class NoOpLightEngine extends ThreadedLevelLightEngine { - private static final ProcessorMailbox MAILBOX = ProcessorMailbox.create(task -> {}, "fawe-no-op"); - private static final ProcessorHandle> HANDLE = ProcessorHandle.of("fawe-no-op", m -> {}); - - public NoOpLightEngine(final ServerChunkCache chunkProvider) { - super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE); - } - - @Override - public CompletableFuture retainData(final ChunkAccess chunk) { - return CompletableFuture.completedFuture(chunk); - } - - @Override - public CompletableFuture lightChunk(final ChunkAccess chunk, final boolean excludeBlocks) { - return CompletableFuture.completedFuture(chunk); - } - - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_3/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_19_3/build.gradle.kts deleted file mode 100644 index 6306d7cf3..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_3/build.gradle.kts +++ /dev/null @@ -1,17 +0,0 @@ -import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension - -plugins { - java -} - -applyPaperweightAdapterConfiguration() - -repositories { - gradlePluginPortal() -} - -dependencies { - // https://papermc.io/repo/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ - the().paperDevBundle("1.19.3-R0.1-20230312.180621-141") - compileOnly(libs.paperlib) -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R2/PaperweightAdapter.java deleted file mode 100644 index ddaa2c6b4..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R2/PaperweightAdapter.java +++ /dev/null @@ -1,1029 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R2; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Sets; -import com.google.common.util.concurrent.Futures; -import com.mojang.datafixers.util.Either; -import com.mojang.serialization.Lifecycle; -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.LongArrayTag; -import com.sk89q.jnbt.LongTag; -import com.sk89q.jnbt.NBTConstants; -import com.sk89q.jnbt.ShortTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.blocks.BaseItem; -import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.extension.platform.Watchdog; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.Constants; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; -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.util.SideEffect; -import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; -import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.ByteBinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; -import com.sk89q.worldedit.util.nbt.EndBinaryTag; -import com.sk89q.worldedit.util.nbt.FloatBinaryTag; -import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; -import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.LongBinaryTag; -import com.sk89q.worldedit.util.nbt.ShortBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; -import com.sk89q.worldedit.world.DataFixer; -import com.sk89q.worldedit.world.RegenOptions; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.BiomeTypes; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.item.ItemType; -import net.minecraft.Util; -import net.minecraft.core.BlockPos; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; -import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.progress.ChunkProgressListener; -import net.minecraft.util.StringRepresentable; -import net.minecraft.util.thread.BlockableEventLoop; -import net.minecraft.world.Clearable; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelSettings; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.StructureBlockEntity; -import net.minecraft.world.level.block.state.StateDefinition; -import net.minecraft.world.level.block.state.properties.DirectionProperty; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.WorldOptions; -import net.minecraft.world.level.storage.LevelStorageSource; -import net.minecraft.world.level.storage.PrimaryLevelData; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World.Environment; -import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_19_R2.CraftServer; -import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_19_R2.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_19_R2.util.CraftMagicNumbers; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; -import org.bukkit.generator.ChunkGenerator; -import org.spigotmc.SpigotConfig; -import org.spigotmc.WatchdogThread; - -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.OptionalInt; -import java.util.OptionalLong; -import java.util.Set; -import java.util.TreeMap; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; -import javax.annotation.Nullable; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -public final class PaperweightAdapter implements BukkitImplAdapter { - - private final Logger LOGGER = Logger.getLogger(getClass().getCanonicalName()); - - private final Field serverWorldsField; - private final Method getChunkFutureMethod; - private final Field chunkProviderExecutorField; - private final Watchdog watchdog; - - // ------------------------------------------------------------------------ - // Code that may break between versions of Minecraft - // ------------------------------------------------------------------------ - - public PaperweightAdapter() throws NoSuchFieldException, NoSuchMethodException { - // A simple test - CraftServer.class.cast(Bukkit.getServer()); - - int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); - if (dataVersion != 3218) { - throw new UnsupportedClassVersionError("Not 1.19.3!"); - } - - serverWorldsField = CraftServer.class.getDeclaredField("worlds"); - serverWorldsField.setAccessible(true); - - getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod( - Refraction.pickName("getChunkFutureMainThread", "c"), - int.class, int.class, ChunkStatus.class, boolean.class - ); - getChunkFutureMethod.setAccessible(true); - - chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField( - Refraction.pickName("mainThreadProcessor", "g") - ); - chunkProviderExecutorField.setAccessible(true); - - new PaperweightDataConverters(CraftMagicNumbers.INSTANCE.getDataVersion(), this).buildUnoptimized(); - - Watchdog watchdog; - try { - Class.forName("org.spigotmc.WatchdogThread"); - watchdog = new SpigotWatchdog(); - } catch (ClassNotFoundException | NoSuchFieldException e) { - try { - watchdog = new MojangWatchdog(((CraftServer) Bukkit.getServer()).getServer()); - } catch (NoSuchFieldException ex) { - watchdog = null; - } - } - this.watchdog = watchdog; - - try { - Class.forName("org.spigotmc.SpigotConfig"); - SpigotConfig.config.set("world-settings.faweregentempworld.verbose", false); - } catch (ClassNotFoundException ignored) { - } - } - - @Override - public DataFixer getDataFixer() { - return PaperweightDataConverters.INSTANCE; - } - - /** - * Read the given NBT data into the given tile entity. - * - * @param tileEntity the tile entity - * @param tag the tag - */ - static void readTagIntoTileEntity(net.minecraft.nbt.CompoundTag tag, BlockEntity tileEntity) { - tileEntity.load(tag); - tileEntity.setChanged(); - } - - /** - * Get the ID string of the given entity. - * - * @param entity the entity - * @return the entity ID - */ - private static String getEntityId(Entity entity) { - return EntityType.getKey(entity.getType()).toString(); - } - - /** - * Create an entity using the given entity ID. - * - * @param id the entity ID - * @param world the world - * @return an entity or null - */ - @Nullable - private static Entity createEntityFromId(String id, net.minecraft.world.level.Level world) { - return EntityType.byString(id).map(t -> t.create(world)).orElse(null); - } - - /** - * Write the given NBT data into the given entity. - * - * @param entity the entity - * @param tag the tag - */ - private static void readTagIntoEntity(net.minecraft.nbt.CompoundTag tag, Entity entity) { - entity.load(tag); - } - - /** - * Write the entity's NBT data to the given tag. - * - * @param entity the entity - * @param tag the tag - */ - private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag tag) { - entity.save(tag); - } - - private static Block getBlockFromType(BlockType blockType) { - - return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK).get(ResourceLocation.tryParse(blockType.getId())); - } - - private static Item getItemFromType(ItemType itemType) { - return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(itemType.getId())); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockData data) { - net.minecraft.world.level.block.state.BlockState state = ((CraftBlockData) data).getState(); - int combinedId = Block.getId(state); - return combinedId == 0 && state.getBlock() != Blocks.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockState state) { - Block mcBlock = getBlockFromType(state.getBlockType()); - net.minecraft.world.level.block.state.BlockState newState = mcBlock.defaultBlockState(); - Map, Object> states = state.getStates(); - newState = applyProperties(mcBlock.getStateDefinition(), newState, states); - final int combinedId = Block.getId(newState); - return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); - } - - @Override - public BlockState getBlock(Location location) { - checkNotNull(location); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - int internalId = Block.getId(blockData); - BlockState state = BlockStateIdAccess.getBlockStateById(internalId); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - - return state; - } - - @Override - public BaseBlock getFullBlock(Location location) { - BlockState state = getBlock(location); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - - // Read the NBT data - BlockEntity te = chunk.getBlockEntity(blockPos); - if (te != null) { - net.minecraft.nbt.CompoundTag tag = te.saveWithId(); - return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); - } - - return state.toBaseBlock(); - } - - @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightWorldNativeAccess(this, - new WeakReference<>(((CraftWorld) world).getHandle())); - } - - private static net.minecraft.core.Direction adapt(Direction face) { - switch (face) { - case NORTH: - return net.minecraft.core.Direction.NORTH; - case SOUTH: - return net.minecraft.core.Direction.SOUTH; - case WEST: - return net.minecraft.core.Direction.WEST; - case EAST: - return net.minecraft.core.Direction.EAST; - case DOWN: - return net.minecraft.core.Direction.DOWN; - case UP: - default: - return net.minecraft.core.Direction.UP; - } - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - private net.minecraft.world.level.block.state.BlockState applyProperties( - StateDefinition stateContainer, - net.minecraft.world.level.block.state.BlockState newState, - Map, Object> states - ) { - for (Map.Entry, Object> state : states.entrySet()) { - net.minecraft.world.level.block.state.properties.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.world.level.block.state.properties.EnumProperty) { - String enumName = (String) value; - value = ((net.minecraft.world.level.block.state.properties.EnumProperty) property) - .getValue(enumName).orElseThrow(() -> - new IllegalStateException( - "Enum property " + property.getName() + " does not contain " + enumName - ) - ); - } - - newState = newState.setValue( - (net.minecraft.world.level.block.state.properties.Property) property, - (Comparable) value - ); - } - return newState; - } - - @Override - public BaseEntity getEntity(org.bukkit.entity.Entity entity) { - checkNotNull(entity); - - CraftEntity craftEntity = ((CraftEntity) entity); - Entity mcEntity = craftEntity.getHandle(); - - // Do not allow creating of passenger entity snapshots, passengers are included in the vehicle entity - if (mcEntity.isPassenger()) { - return null; - } - - String id = getEntityId(mcEntity); - - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - readEntityIntoTag(mcEntity, tag); - return new BaseEntity( - com.sk89q.worldedit.world.entity.EntityTypes.get(id), - LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag)) - ); - } - - @Nullable - @Override - public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state) { - checkNotNull(location); - checkNotNull(state); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - ServerLevel worldServer = craftWorld.getHandle(); - - Entity createdEntity = createEntityFromId(state.getType().getId(), craftWorld.getHandle()); - - if (createdEntity != null) { - CompoundBinaryTag nativeTag = state.getNbt(); - if (nativeTag != null) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(nativeTag); - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - readTagIntoEntity(tag, createdEntity); - } - - createdEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - - worldServer.addFreshEntity(createdEntity, SpawnReason.CUSTOM); - return createdEntity.getBukkitEntity(); - } else { - return null; - } - } - - // This removes all unwanted tags from the main entity and all its passengers - private void removeUnwantedEntityTagsRecursively(net.minecraft.nbt.CompoundTag tag) { - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - - // Adapted from net.minecraft.world.entity.EntityType#loadEntityRecursive - if (tag.contains("Passengers", NBTConstants.TYPE_LIST)) { - net.minecraft.nbt.ListTag nbttaglist = tag.getList("Passengers", NBTConstants.TYPE_COMPOUND); - - for (int i = 0; i < nbttaglist.size(); ++i) { - removeUnwantedEntityTagsRecursively(nbttaglist.getCompound(i)); - } - } - } - - @Override - public Component getRichBlockName(BlockType blockType) { - return TranslatableComponent.of(getBlockFromType(blockType).getDescriptionId()); - } - - @Override - public Component getRichItemName(ItemType itemType) { - return TranslatableComponent.of(getItemFromType(itemType).getDescriptionId()); - } - - @Override - public Component getRichItemName(BaseItemStack itemStack) { - return TranslatableComponent.of(CraftItemStack.asNMSCopy(BukkitAdapter.adapt(itemStack)).getDescriptionId()); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - private static final LoadingCache> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { - @Override - public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else if (state instanceof DirectionProperty) { - return new DirectionalProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - return new EnumProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else { - throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); - } - } - }); - - @SuppressWarnings({ "rawtypes" }) - @Override - public Map> getProperties(BlockType blockType) { - Map> properties = new TreeMap<>(); - Block block = getBlockFromType(blockType); - StateDefinition blockStateList = - block.getStateDefinition(); - for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { - Property property = PROPERTY_CACHE.getUnchecked(state); - properties.put(property.getName(), property); - } - return properties; - } - - @Override - public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { - ((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create( - new StructureBlockEntity( - new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()), - Blocks.STRUCTURE_BLOCK.defaultBlockState() - ), - __ -> (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) - )); - } - - @Override - public void sendFakeOP(Player player) { - ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( - ((CraftPlayer) player).getHandle(), (byte) 28 - )); - } - - @Override - public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { - ItemStack stack = new ItemStack( - DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().getId())), - item.getAmount() - ); - stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData()))); - return CraftItemStack.asCraftMirror(stack); - } - - @Override - public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { - final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); - final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); - weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); - return weStack; - } - - private final LoadingCache fakePlayers - = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); - - @Override - public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) { - CraftWorld craftWorld = (CraftWorld) world; - ServerLevel worldServer = craftWorld.getHandle(); - ItemStack stack = CraftItemStack.asNMSCopy(BukkitAdapter.adapt(item instanceof BaseItemStack - ? ((BaseItemStack) item) : new BaseItemStack(item.getType(), item.getNbtData(), 1))); - stack.setTag((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData())); - - PaperweightFakePlayer fakePlayer; - try { - fakePlayer = fakePlayers.get(worldServer); - } catch (ExecutionException ignored) { - return false; - } - fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); - fakePlayer.absMoveTo(position.getBlockX(), position.getBlockY(), position.getBlockZ(), - (float) face.toVector().toYaw(), (float) face.toVector().toPitch()); - - final BlockPos blockPos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos); - final net.minecraft.core.Direction enumFacing = adapt(face); - BlockHitResult rayTrace = new BlockHitResult(blockVec, enumFacing, blockPos, false); - UseOnContext context = new UseOnContext(fakePlayer, InteractionHand.MAIN_HAND, rayTrace); - InteractionResult result = stack.useOn(context, InteractionHand.MAIN_HAND); - if (result != InteractionResult.SUCCESS) { - if (worldServer.getBlockState(blockPos).use(worldServer, fakePlayer, InteractionHand.MAIN_HAND, rayTrace).consumesAction()) { - result = InteractionResult.SUCCESS; - } else { - result = stack.getItem().use(worldServer, fakePlayer, InteractionHand.MAIN_HAND).getResult(); - } - } - - return result == InteractionResult.SUCCESS; - } - - @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 position, BlockState blockState) { - int internalId = BlockStateIdAccess.getBlockStateId(blockState); - net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId); - return blockData.canSurvive(((CraftWorld) world).getHandle(), new BlockPos(position.getX(), position.getY(), position.getZ())); - } - - @Override - public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) { - try { - doRegen(bukkitWorld, region, extent, options); - } catch (Exception e) { - throw new IllegalStateException("Regen failed.", e); - } - - return true; - } - - private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { - Environment env = bukkitWorld.getEnvironment(); - ChunkGenerator gen = bukkitWorld.getGenerator(); - - Path tempDir = Files.createTempDirectory("WorldEditWorldGen"); - LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir); - ResourceKey worldDimKey = getWorldDimKey(env); - try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { - ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); - PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() - .getWorldData().overworldData(); - WorldOptions originalOpts = levelProperties.worldGenOptions(); - - long seed = options.getSeed().orElse(originalWorld.getSeed()); - WorldOptions newOpts = options.getSeed().isPresent() - ? originalOpts.withSeed(OptionalLong.of(seed)) - : originalOpts; - - LevelSettings newWorldSettings = new LevelSettings( - "faweregentempworld", - levelProperties.settings.gameType(), - levelProperties.settings.hardcore(), - levelProperties.settings.difficulty(), - levelProperties.settings.allowCommands(), - levelProperties.settings.gameRules(), - levelProperties.settings.getDataConfiguration() - ); - - PrimaryLevelData.SpecialWorldProperty specialWorldProperty = - levelProperties.isFlatWorld() - ? PrimaryLevelData.SpecialWorldProperty.FLAT - : levelProperties.isDebugWorld() - ? PrimaryLevelData.SpecialWorldProperty.DEBUG - : PrimaryLevelData.SpecialWorldProperty.NONE; - - PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable()); - - ServerLevel freshWorld = new ServerLevel( - originalWorld.getServer(), - originalWorld.getServer().executor, - session, newWorldData, - originalWorld.dimension(), - new LevelStem( - originalWorld.dimensionTypeRegistration(), - originalWorld.getChunkSource().getGenerator() - ), - new NoOpWorldLoadListener(), - originalWorld.isDebug(), - seed, - ImmutableList.of(), - false, - env, - gen, - bukkitWorld.getBiomeProvider() - ); - try { - regenForWorld(region, extent, freshWorld, options); - } finally { - freshWorld.getChunkSource().close(false); - } - } finally { - try { - @SuppressWarnings("unchecked") - Map map = (Map) serverWorldsField.get(Bukkit.getServer()); - map.remove("faweregentempworld"); - } catch (IllegalAccessException ignored) { - } - SafeFiles.tryHardToDeleteDir(tempDir); - } - } - - private BiomeType adapt(ServerLevel serverWorld, Biome origBiome) { - ResourceLocation key = serverWorld.registryAccess().registryOrThrow(Registries.BIOME).getKey(origBiome); - if (key == null) { - return null; - } - return BiomeTypes.get(key.toString()); - } - - @SuppressWarnings("unchecked") - private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld, RegenOptions options) throws WorldEditException { - List> chunkLoadings = submitChunkLoadTasks(region, serverWorld); - BlockableEventLoop executor; - try { - executor = (BlockableEventLoop) chunkProviderExecutorField.get(serverWorld.getChunkSource()); - } catch (IllegalAccessException e) { - throw new IllegalStateException("Couldn't get executor for chunk loading.", e); - } - executor.managedBlock(() -> { - // bail out early if a future fails - if (chunkLoadings.stream().anyMatch(ftr -> - ftr.isDone() && Futures.getUnchecked(ftr) == null - )) { - return false; - } - return chunkLoadings.stream().allMatch(CompletableFuture::isDone); - }); - Map chunks = new HashMap<>(); - for (CompletableFuture future : chunkLoadings) { - @Nullable - ChunkAccess chunk = future.getNow(null); - checkState(chunk != null, "Failed to generate a chunk, regen failed."); - chunks.put(chunk.getPos(), chunk); - } - - for (BlockVector3 vec : region) { - BlockPos pos = new BlockPos(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()); - ChunkAccess chunk = chunks.get(new ChunkPos(pos)); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(pos); - int internalId = Block.getId(blockData); - BlockStateHolder state = BlockStateIdAccess.getBlockStateById(internalId); - Objects.requireNonNull(state); - BlockEntity blockEntity = chunk.getBlockEntity(pos); - if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); - state = state.toBaseBlock(((CompoundBinaryTag) toNativeBinary(tag))); - } - extent.setBlock(vec, state.toBaseBlock()); - if (options.shouldRegenBiomes()) { - Biome origBiome = chunk.getNoiseBiome(vec.getX(), vec.getY(), vec.getZ()).value(); - BiomeType adaptedBiome = adapt(serverWorld, origBiome); - if (adaptedBiome != null) { - extent.setBiome(vec, adaptedBiome); - } - } - } - } - - @SuppressWarnings("unchecked") - private List> submitChunkLoadTasks(Region region, ServerLevel serverWorld) { - ServerChunkCache chunkManager = serverWorld.getChunkSource(); - List> chunkLoadings = new ArrayList<>(); - // Pre-gen all the chunks - for (BlockVector2 chunk : region.getChunks()) { - try { - //noinspection unchecked - chunkLoadings.add( - ((CompletableFuture>) - getChunkFutureMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) - .thenApply(either -> either.left().orElse(null)) - ); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalStateException("Couldn't load chunk for regen.", e); - } - } - return chunkLoadings; - } - - private ResourceKey getWorldDimKey(Environment env) { - switch (env) { - case NETHER: - return LevelStem.NETHER; - case THE_END: - return LevelStem.END; - case NORMAL: - default: - return LevelStem.OVERWORLD; - } - } - - private static final Set SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( - SideEffect.NEIGHBORS, - SideEffect.LIGHTING, - SideEffect.VALIDATION, - SideEffect.ENTITY_AI, - SideEffect.EVENTS, - SideEffect.UPDATE - ); - - @Override - public Set getSupportedSideEffects() { - return SUPPORTED_SIDE_EFFECTS; - } - - @Override - public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) { - ServerLevel originalWorld = ((CraftWorld) world).getHandle(); - - BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); - if (entity instanceof Clearable) { - ((Clearable) entity).clearContent(); - return true; - } - return false; - } - - // ------------------------------------------------------------------------ - // Code that is less likely to break - // ------------------------------------------------------------------------ - - /** - * Converts from a non-native NMS NBT structure to a native WorldEdit NBT - * structure. - * - * @param foreign non-native NMS NBT structure - * @return native WorldEdit NBT structure - */ - @Override - public BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { - if (foreign == null) { - return null; - } - if (foreign instanceof net.minecraft.nbt.CompoundTag) { - Map values = new HashMap<>(); - Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); - - for (String str : foreignKeys) { - net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); - values.put(str, toNativeBinary(base)); - } - return CompoundBinaryTag.from(values); - } else if (foreign instanceof net.minecraft.nbt.ByteTag) { - return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); - } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { - return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); - } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { - return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); - } else if (foreign instanceof net.minecraft.nbt.FloatTag) { - return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); - } else if (foreign instanceof net.minecraft.nbt.IntTag) { - return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); - } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { - return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); - } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { - return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); - } else if (foreign instanceof net.minecraft.nbt.ListTag) { - try { - return toNativeList((net.minecraft.nbt.ListTag) foreign); - } catch (Throwable e) { - LOGGER.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); - return ListBinaryTag.empty(); - } - } else if (foreign instanceof net.minecraft.nbt.LongTag) { - return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); - } else if (foreign instanceof net.minecraft.nbt.ShortTag) { - return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); - } else if (foreign instanceof net.minecraft.nbt.StringTag) { - return StringBinaryTag.of(foreign.getAsString()); - } else if (foreign instanceof net.minecraft.nbt.EndTag) { - return EndBinaryTag.get(); - } else { - throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); - } - } - - /** - * Convert a foreign NBT list tag into a native WorldEdit one. - * - * @param foreign the foreign tag - * @return the converted tag - * @throws SecurityException on error - * @throws IllegalArgumentException on error - */ - private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { - ListBinaryTag.Builder values = ListBinaryTag.builder(); - - for (net.minecraft.nbt.Tag tag : foreign) { - values.add(toNativeBinary(tag)); - } - - return values.build(); - } - - /** - * Converts a WorldEdit-native NBT structure to a NMS structure. - * - * @param foreign structure to convert - * @return non-native structure - */ - @Override - public net.minecraft.nbt.Tag fromNativeBinary(BinaryTag foreign) { - if (foreign == null) { - return null; - } - if (foreign instanceof CompoundBinaryTag) { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - for (String key : ((CompoundBinaryTag) foreign).keySet()) { - tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); - } - return tag; - } else if (foreign instanceof ByteBinaryTag) { - return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); - } else if (foreign instanceof ByteArrayBinaryTag) { - return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); - } else if (foreign instanceof DoubleBinaryTag) { - return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); - } else if (foreign instanceof FloatBinaryTag) { - return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); - } else if (foreign instanceof IntBinaryTag) { - return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); - } else if (foreign instanceof IntArrayBinaryTag) { - return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); - } else if (foreign instanceof LongArrayBinaryTag) { - return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); - } else if (foreign instanceof ListBinaryTag) { - net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); - ListBinaryTag foreignList = (ListBinaryTag) foreign; - for (BinaryTag t : foreignList) { - tag.add(fromNativeBinary(t)); - } - return tag; - } else if (foreign instanceof LongBinaryTag) { - return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); - } else if (foreign instanceof ShortBinaryTag) { - return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); - } else if (foreign instanceof StringBinaryTag) { - return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); - } else if (foreign instanceof EndBinaryTag) { - return net.minecraft.nbt.EndTag.INSTANCE; - } else { - throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); - } - } - - @Override - public boolean supportsWatchdog() { - return watchdog != null; - } - - @Override - public void tickWatchdog() { - watchdog.tick(); - } - - private class SpigotWatchdog implements Watchdog { - private final Field instanceField; - private final Field lastTickField; - - SpigotWatchdog() throws NoSuchFieldException { - Field instanceField = WatchdogThread.class.getDeclaredField("instance"); - instanceField.setAccessible(true); - this.instanceField = instanceField; - - Field lastTickField = WatchdogThread.class.getDeclaredField("lastTick"); - lastTickField.setAccessible(true); - this.lastTickField = lastTickField; - } - - @Override - public void tick() { - try { - WatchdogThread instance = (WatchdogThread) this.instanceField.get(null); - if ((long) lastTickField.get(instance) != 0) { - WatchdogThread.tick(); - } - } catch (IllegalAccessException e) { - LOGGER.log(Level.WARNING, "Failed to tick watchdog", e); - } - } - } - - private static class MojangWatchdog implements Watchdog { - private final DedicatedServer server; - private final Field tickField; - - MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { - this.server = server; - Field tickField = MinecraftServer.class.getDeclaredField( - Refraction.pickName("nextTickTime", "ag") - ); - if (tickField.getType() != long.class) { - throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); - } - tickField.setAccessible(true); - this.tickField = tickField; - } - - @Override - public void tick() { - try { - tickField.set(server, Util.getMillis()); - } catch (IllegalAccessException ignored) { - } - } - } - - private static class NoOpWorldLoadListener implements ChunkProgressListener { - @Override - public void updateSpawnPos(ChunkPos spawnPos) { - } - - @Override - public void onStatusChange(ChunkPos pos, @org.jetbrains.annotations.Nullable ChunkStatus status) { - } - - @Override - public void start() { - } - - @Override - public void stop() { - } - - @Override - public void setChunkRadius(int radius) { - } - } -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R2/PaperweightDataConverters.java b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R2/PaperweightDataConverters.java deleted file mode 100644 index 7e735efdb..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R2/PaperweightDataConverters.java +++ /dev/null @@ -1,2800 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R2; - -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.schemas.Schema; -import com.mojang.serialization.Dynamic; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import net.minecraft.core.Direction; -import net.minecraft.nbt.NbtOps; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.GsonHelper; -import net.minecraft.util.StringUtil; -import net.minecraft.util.datafix.DataFixers; -import net.minecraft.util.datafix.fixes.References; -import net.minecraft.world.item.DyeColor; -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({ "rawtypes", "unchecked" }) -class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { - - //FAWE start - BinaryTag - @SuppressWarnings("unchecked") - @Override - public T fixUp(FixType type, T original, int srcVer) { - if (type == FixTypes.CHUNK) { - return (T) fixChunk((CompoundBinaryTag) original, srcVer); - } else if (type == FixTypes.BLOCK_ENTITY) { - return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); - } else if (type == FixTypes.ENTITY) { - return (T) fixEntity((CompoundBinaryTag) 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 CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); - } - - private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); - } - - private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); - } - //FAWE end - - 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(References.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.contains("Properties", 10)) { - sb.append('['); - net.minecraft.nbt.CompoundTag props = tagCompound.getCompound("Properties"); - sb.append(props.getAllKeys().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, References.BIOME); - } - - private String fixItemType(String key, int srcVer) { - return fixName(key, srcVer, References.ITEM_NAME); - } - - private static String fixName(String key, int srcVer, TypeReference type) { - return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, net.minecraft.nbt.StringTag.valueOf(key)), srcVer, DATA_VERSION) - .getValue().getAsString(); - } - - private final PaperweightAdapter adapter; - - private static final NbtOps OPS_NBT = NbtOps.INSTANCE; - private static final int LEGACY_VERSION = 1343; - private static int DATA_VERSION; - static PaperweightDataConverters 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(References.LEVEL), - PLAYER(References.PLAYER), - CHUNK(References.CHUNK), - BLOCK_ENTITY(References.BLOCK_ENTITY), - ENTITY(References.ENTITY), - ITEM_INSTANCE(References.ITEM_STACK), - OPTIONS(References.OPTIONS), - STRUCTURE(References.STRUCTURE); - - private final TypeReference type; - - LegacyType(TypeReference type) { - this.type = type; - DFU_TO_LEGACY.put(type.typeName(), this); - } - - public TypeReference getDFUType() { - return type; - } - } - - PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { - super(dataVersion); - DATA_VERSION = dataVersion; - INSTANCE = this; - this.adapter = adapter; - registerConverters(); - registerInspectors(); - } - - - // Called after fixers are built and ready for FIXING - @Override - public DataFixer buildUnoptimized() { - return this.fixer = new WrappedDataFixer(DataFixers.getDataFixer()); - } - - @Override - public DataFixer buildOptimized(Executor executor) { - return buildUnoptimized(); - } - - @SuppressWarnings("unchecked") - 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 = PaperweightDataConverters.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 = PaperweightDataConverters.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.contains("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 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, 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.contains(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.contains(key, 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound.getList(key, 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - nbttaglist.set(j, convert(LegacyType.ITEM_INSTANCE, nbttaglist.getCompound(j), sourceVer, targetVer)); - } - } - - } - - private static class DataConverterEquipment implements DataConverter { - - DataConverterEquipment() { - } - - public int getDataVersion() { - return 100; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("Equipment", 10); - net.minecraft.nbt.ListTag nbttaglist1; - - if (!nbttaglist.isEmpty() && !cmp.contains("HandItems", 10)) { - nbttaglist1 = new net.minecraft.nbt.ListTag(); - nbttaglist1.add(nbttaglist.get(0)); - nbttaglist1.add(new net.minecraft.nbt.CompoundTag()); - cmp.put("HandItems", nbttaglist1); - } - - if (nbttaglist.size() > 1 && !cmp.contains("ArmorItem", 10)) { - nbttaglist1 = new net.minecraft.nbt.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.contains("DropChances", 9)) { - nbttaglist1 = cmp.getList("DropChances", 5); - net.minecraft.nbt.ListTag nbttaglist2; - - if (!cmp.contains("HandDropChances", 10)) { - nbttaglist2 = new net.minecraft.nbt.ListTag(); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(0))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(0.0F)); - cmp.put("HandDropChances", nbttaglist2); - } - - if (!cmp.contains("ArmorDropChances", 10)) { - nbttaglist2 = new net.minecraft.nbt.ListTag(); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(1))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(2))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(3))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(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); - } - } - - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (!cmp.contains("tag", 10)) { - return cmp; - } else { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("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.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 { - - DataInspectorEntity() { - } - - 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.contains("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; - - 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (this.key.equals(new ResourceLocation(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) { - PaperweightDataConverters.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) { - PaperweightDataConverters.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.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"; - // Paper start - materials[409] = "minecraft:prismarine_shard"; - materials[410] = "minecraft:prismarine_crystals"; - materials[411] = "minecraft:rabbit"; - materials[412] = "minecraft:cooked_rabbit"; - materials[413] = "minecraft:rabbit_stew"; - materials[414] = "minecraft:rabbit_foot"; - materials[415] = "minecraft:rabbit_hide"; - materials[416] = "minecraft:armor_stand"; - materials[423] = "minecraft:mutton"; - materials[424] = "minecraft:cooked_mutton"; - materials[425] = "minecraft:banner"; - materials[426] = "minecraft:end_crystal"; - materials[427] = "minecraft:spruce_door"; - materials[428] = "minecraft:birch_door"; - materials[429] = "minecraft:jungle_door"; - materials[430] = "minecraft:acacia_door"; - materials[431] = "minecraft:dark_oak_door"; - materials[432] = "minecraft:chorus_fruit"; - materials[433] = "minecraft:chorus_fruit_popped"; - materials[434] = "minecraft:beetroot"; - materials[435] = "minecraft:beetroot_seeds"; - materials[436] = "minecraft:beetroot_soup"; - materials[437] = "minecraft:dragon_breath"; - materials[438] = "minecraft:splash_potion"; - materials[439] = "minecraft:spectral_arrow"; - materials[440] = "minecraft:tipped_arrow"; - materials[441] = "minecraft:lingering_potion"; - materials[442] = "minecraft:shield"; - materials[443] = "minecraft:elytra"; - materials[444] = "minecraft:spruce_boat"; - materials[445] = "minecraft:birch_boat"; - materials[446] = "minecraft:jungle_boat"; - materials[447] = "minecraft:acacia_boat"; - materials[448] = "minecraft:dark_oak_boat"; - materials[449] = "minecraft:totem_of_undying"; - materials[450] = "minecraft:shulker_shell"; - materials[452] = "minecraft:iron_nugget"; - materials[453] = "minecraft:knowledge_book"; - // Paper end - } - } - - 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.contains("tag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("BlockEntityTag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); - - if (nbttagcompound2.contains("Base", 99)) { - cmp.putShort("Damage", (short) (nbttagcompound2.getShort("Base") & 15)); - if (nbttagcompound1.contains("display", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound3 = nbttagcompound1.getCompound("display"); - - if (nbttagcompound3.contains("Lore", 9)) { - net.minecraft.nbt.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.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 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.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("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.contains("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.contains("SpawnPotentials", 9)) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); - - for (int i = 0; i < nbttaglist.size(); ++i) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist.getCompound(i); - - if (nbttagcompound2.contains("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.contains("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.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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("EntityHorse".equals(cmp.getString("id")) && !cmp.contains("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.contains("Facing", 99)) { - Direction enumdirection; - - if (cmp.contains("Direction", 99)) { - enumdirection = Direction.from2DDataValue(cmp.getByte("Direction")); - cmp.putInt("TileX", cmp.getInt("TileX") + enumdirection.getStepX()); - cmp.putInt("TileY", cmp.getInt("TileY") + enumdirection.getStepY()); - cmp.putInt("TileZ", cmp.getInt("TileZ") + enumdirection.getStepZ()); - cmp.remove("Direction"); - if (flag1 && cmp.contains("ItemRotation", 99)) { - cmp.putByte("ItemRotation", (byte) (cmp.getByte("ItemRotation") * 2)); - } - } else { - enumdirection = Direction.from2DDataValue(cmp.getByte("Dir")); - cmp.remove("Dir"); - } - - cmp.putByte("Facing", (byte) enumdirection.get2DDataValue()); - } - - 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) { - net.minecraft.nbt.ListTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - while (cmp.contains("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) { - net.minecraft.nbt.ListTag nbttaglist = new net.minecraft.nbt.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.contains("pages", 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("pages", 8); - - for (int i = 0; i < nbttaglist.size(); ++i) { - String s = nbttaglist.getString(i); - Component object = null; - - if (!"null".equals(s) && !StringUtil.isNullOrEmpty(s)) { - if ((s.charAt(0) != 34 || s.charAt(s.length() - 1) != 34) && (s.charAt(0) != 123 || s.charAt(s.length() - 1) != 125)) { - object = Component.literal(s); - } else { - try { - object = GsonHelper.fromJson(DataConverterSignText.a, s, Component.class, true); - if (object == null) { - object = Component.literal(""); - } - } catch (JsonParseException jsonparseexception) { - ; - } - - if (object == null) { - try { - object = Component.Serializer.fromJson(s); - } catch (JsonParseException jsonparseexception1) { - ; - } - } - - if (object == null) { - try { - object = Component.Serializer.fromJsonLenient(s); - } catch (JsonParseException jsonparseexception2) { - ; - } - } - - if (object == null) { - object = Component.literal(s); - } - } - } else { - object = Component.literal(""); - } - - nbttaglist.set(i, net.minecraft.nbt.StringTag.valueOf(Component.Serializer.toJson(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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 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 0: - default: - break; - - 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"); - } - - 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 0: - default: - cmp.putString("id", "Horse"); - break; - - 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"); - } - - 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.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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:shulker_box".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("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.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 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(PaperweightDataConverters.class); - - DataConverterBedBlock() { - } - - public int getDataVersion() { - return 1125; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - try { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); - int i = nbttagcompound1.getInt("xPos"); - int j = nbttagcompound1.getInt("zPos"); - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("TileEntities", 10); - net.minecraft.nbt.ListTag nbttaglist1 = nbttagcompound1.getList("Sections", 10); - - for (int k = 0; k < nbttaglist1.size(); ++k) { - net.minecraft.nbt.CompoundTag 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; - net.minecraft.nbt.CompoundTag nbttagcompound3 = new net.minecraft.nbt.CompoundTag(); - - nbttagcompound3.putString("id", "bed"); - nbttagcompound3.putInt("x", i1 + (i << 4)); - nbttagcompound3.putInt("y", j1 + (b0 << 4)); - nbttagcompound3.putInt("z", k1 + (j << 4)); - nbttaglist.add(nbttagcompound3); - } - } - } - } catch (Exception exception) { - DataConverterBedBlock.a.warn("Unable to datafix Bed blocks, level format may be missing tags."); - } - - return cmp; - } - } - - private static class DataConverterBedItem implements DataConverter { - - DataConverterBedItem() { - } - - public int getDataVersion() { - return 1125; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:bed".equals(cmp.getString("id")) && cmp.getShort("Damage") == 0) { - cmp.putShort("Damage", (short) DyeColor.RED.getId()); - } - - return cmp; - } - } - - private static class DataConverterSignText implements DataConverter { - - public static final Gson a = new GsonBuilder().registerTypeAdapter(Component.class, new JsonDeserializer() { - MutableComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { - if (jsonelement.isJsonPrimitive()) { - return Component.literal(jsonelement.getAsString()); - } else if (jsonelement.isJsonArray()) { - JsonArray jsonarray = jsonelement.getAsJsonArray(); - MutableComponent ichatbasecomponent = null; - Iterator iterator = jsonarray.iterator(); - - while (iterator.hasNext()) { - JsonElement jsonelement1 = (JsonElement) iterator.next(); - MutableComponent ichatbasecomponent1 = this.a(jsonelement1, jsonelement1.getClass(), jsondeserializationcontext); - - if (ichatbasecomponent == null) { - ichatbasecomponent = ichatbasecomponent1; - } else { - ichatbasecomponent.append(ichatbasecomponent1); - } - } - - return ichatbasecomponent; - } 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); - Component object = null; - - if (!"null".equals(s1) && !StringUtil.isNullOrEmpty(s1)) { - if ((s1.charAt(0) != 34 || s1.charAt(s1.length() - 1) != 34) && (s1.charAt(0) != 123 || s1.charAt(s1.length() - 1) != 125)) { - object = Component.literal(s1); - } else { - try { - object = GsonHelper.fromJson(DataConverterSignText.a, s1, Component.class, true); - if (object == null) { - object = Component.literal(""); - } - } catch (JsonParseException jsonparseexception) { - ; - } - - if (object == null) { - try { - object = Component.Serializer.fromJson(s1); - } catch (JsonParseException jsonparseexception1) { - ; - } - } - - if (object == null) { - try { - object = Component.Serializer.fromJsonLenient(s1); - } catch (JsonParseException jsonparseexception2) { - ; - } - } - - if (object == null) { - object = Component.literal(s1); - } - } - } else { - object = Component.literal(""); - } - - nbttagcompound.putString(s, Component.Serializer.toJson(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.contains("RootVehicle", 10)) { - net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - net.minecraft.nbt.ListTag nbttaglist; - int j; - net.minecraft.nbt.CompoundTag nbttagcompound1; - - if (cmp.contains("entities", 9)) { - nbttaglist = cmp.getList("entities", 10); - - for (j = 0; j < nbttaglist.size(); ++j) { - nbttagcompound1 = (net.minecraft.nbt.CompoundTag) 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 = (net.minecraft.nbt.CompoundTag) 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (cmp.contains("Level", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); - net.minecraft.nbt.ListTag 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, (net.minecraft.nbt.CompoundTag) 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, (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.contains("Passengers", 9)) { - net.minecraft.nbt.ListTag 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 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.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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (entityVillager.equals(new ResourceLocation(cmp.getString("id"))) && cmp.contains("Offers", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Offers"); - - if (nbttagcompound1.contains("Recipes", 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("Recipes", 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (tileEntityMobSpawner.equals(new ResourceLocation(cmp.getString("id")))) { - if (cmp.contains("SpawnPotentials", 9)) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - net.minecraft.nbt.CompoundTag 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 net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag 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-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R2/PaperweightFakePlayer.java b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R2/PaperweightFakePlayer.java deleted file mode 100644 index 874b5323f..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R2/PaperweightFakePlayer.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 General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R2; - -import com.mojang.authlib.GameProfile; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ServerboundClientInformationPacket; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.stats.Stat; -import net.minecraft.world.MenuProvider; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.block.entity.SignBlockEntity; -import net.minecraft.world.phys.Vec3; -import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; - -import java.util.OptionalInt; -import java.util.UUID; - -class PaperweightFakePlayer extends ServerPlayer { - private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]"); - private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D); - - PaperweightFakePlayer(ServerLevel world) { - super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE); - } - - @Override - public Vec3 position() { - return ORIGIN; - } - - @Override - public void tick() { - } - - @Override - public void die(DamageSource damagesource) { - } - - @Override - public Entity changeDimension(ServerLevel worldserver, TeleportCause cause) { - return this; - } - - @Override - public OptionalInt openMenu(MenuProvider factory) { - return OptionalInt.empty(); - } - - @Override - public void updateOptions(ServerboundClientInformationPacket packet) { - } - - @Override - public void displayClientMessage(Component message, boolean actionBar) { - } - - @Override - public void awardStat(Stat stat, int amount) { - } - - @Override - public void awardStat(Stat stat) { - } - - @Override - public boolean isInvulnerableTo(DamageSource damageSource) { - return true; - } - - @Override - public void openTextEdit(SignBlockEntity sign) { - } -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R2/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R2/PaperweightWorldNativeAccess.java deleted file mode 100644 index 32d5682b1..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R2/PaperweightWorldNativeAccess.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R2; - -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.world.block.BlockState; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.chunk.LevelChunk; -import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData; -import org.bukkit.event.block.BlockPhysicsEvent; - -import java.lang.ref.WeakReference; -import java.util.Objects; -import javax.annotation.Nullable; - -public class PaperweightWorldNativeAccess implements WorldNativeAccess { - private static final int UPDATE = 1; - private static final int NOTIFY = 2; - - private final PaperweightAdapter adapter; - private final WeakReference world; - private SideEffectSet sideEffectSet; - - public PaperweightWorldNativeAccess(PaperweightAdapter adapter, WeakReference world) { - this.adapter = adapter; - this.world = world; - } - - private ServerLevel getWorld() { - return Objects.requireNonNull(world.get(), "The reference to the world was lost"); - } - - @Override - public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { - this.sideEffectSet = sideEffectSet; - } - - @Override - public LevelChunk getChunk(int x, int z) { - return getWorld().getChunk(x, z); - } - - @Override - public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) { - int stateId = BlockStateIdAccess.getBlockStateId(state); - return BlockStateIdAccess.isValidInternalId(stateId) - ? Block.stateById(stateId) - : ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk chunk, BlockPos position) { - return chunk.getBlockState(position); - } - - @Nullable - @Override - public net.minecraft.world.level.block.state.BlockState setBlockState(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState state) { - return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE)); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(net.minecraft.world.level.block.state.BlockState block, BlockPos position) { - return Block.updateFromNeighbourShapes(block, getWorld(), position); - } - - @Override - public BlockPos getPosition(int x, int y, int z) { - return new BlockPos(x, y, z); - } - - @Override - public void updateLightingForBlock(BlockPos position) { - getWorld().getChunkSource().getLightEngine().checkBlock(position); - } - - @Override - public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { - return false; - } - - @Override - public void notifyBlockUpdate(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { - if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { - getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY); - } - } - - @Override - public boolean isChunkTicking(LevelChunk chunk) { - return chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); - } - - @Override - public void markBlockChanged(LevelChunk chunk, BlockPos position) { - if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { - getWorld().getChunkSource().blockChanged(position); - } - } - - @Override - public void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { - ServerLevel world = getWorld(); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - world.updateNeighborsAt(pos, oldState.getBlock()); - } else { - // When we don't want events, manually run the physics without them. - Block block = oldState.getBlock(); - fireNeighborChanged(pos, world, block, pos.west()); - fireNeighborChanged(pos, world, block, pos.east()); - fireNeighborChanged(pos, world, block, pos.below()); - fireNeighborChanged(pos, world, block, pos.above()); - fireNeighborChanged(pos, world, block, pos.north()); - fireNeighborChanged(pos, world, block, pos.south()); - } - if (newState.hasAnalogOutputSignal()) { - world.updateNeighbourForOutputSignal(pos, newState.getBlock()); - } - } - - // Not sure why neighborChanged is deprecated - @SuppressWarnings("deprecation") - private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { - world.getBlockState(neighborPos).neighborChanged(world, neighborPos, block, pos, false); - } - - @Override - public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) { - ServerLevel world = getWorld(); - // a == updateNeighbors - // b == updateDiagonalNeighbors - oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - CraftWorld craftWorld = world.getWorld(); - BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState)); - world.getCraftServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - } - newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit); - newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); - } - - @Override - public void onBlockStateChange(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { - getWorld().onBlockStateChange(pos, oldState, newState); - } - - @Override - public void flush() { - - } -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightBlockMaterial.java deleted file mode 100644 index 69528e201..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightBlockMaterial.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2; - -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.util.ReflectionUtil; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.world.registry.BlockMaterial; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.EmptyBlockGetter; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.EntityBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.Material; -import net.minecraft.world.level.material.PushReaction; -import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData; - -public class PaperweightBlockMaterial implements BlockMaterial { - - private final Block block; - private final BlockState blockState; - private final Material material; - private final boolean isTranslucent; - private final CraftBlockData craftBlockData; - private final org.bukkit.Material craftMaterial; - private final int opacity; - private final CompoundTag tile; - - public PaperweightBlockMaterial(Block block) { - this(block, block.defaultBlockState()); - } - - public PaperweightBlockMaterial(Block block, BlockState blockState) { - this.block = block; - this.blockState = blockState; - this.material = blockState.getMaterial(); - this.craftBlockData = CraftBlockData.fromData(blockState); - this.craftMaterial = craftBlockData.getMaterial(); - BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, - Refraction.pickName("properties", "aP")); - this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo, - Refraction.pickName("canOcclude", "n") - ); - opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); - BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity( - BlockPos.ZERO, - blockState - ); - tile = tileEntity == null - ? null - : new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); - } - - public Block getBlock() { - return block; - } - - public BlockState getState() { - return blockState; - } - - public CraftBlockData getCraftBlockData() { - return craftBlockData; - } - - public Material getMaterial() { - return material; - } - - @Override - public boolean isAir() { - return blockState.isAir(); - } - - @Override - public boolean isFullCube() { - return craftMaterial.isOccluding(); - } - - @Override - public boolean isOpaque() { - return material.isSolidBlocking(); - } - - @Override - public boolean isPowerSource() { - return blockState.isSignalSource(); - } - - @Override - public boolean isLiquid() { - return material.isLiquid(); - } - - @Override - public boolean isSolid() { - return material.isSolid(); - } - - @Override - public float getHardness() { - return craftBlockData.getState().destroySpeed; - } - - @Override - public float getResistance() { - return block.getExplosionResistance(); - } - - @Override - public float getSlipperiness() { - return block.getFriction(); - } - - @Override - public int getLightValue() { - return blockState.getLightEmission(); - } - - @Override - public int getLightOpacity() { - return opacity; - } - - @Override - public boolean isFragileWhenPushed() { - return material.getPushReaction() == PushReaction.DESTROY; - } - - @Override - public boolean isUnpushable() { - return material.getPushReaction() == PushReaction.BLOCK; - } - - @Override - public boolean isTicksRandomly() { - return block.isRandomlyTicking(blockState); - } - - @Override - public boolean isMovementBlocker() { - return material.isSolid(); - } - - @Override - public boolean isBurnable() { - return material.isFlammable(); - } - - @Override - public boolean isToolRequired() { - // Removed in 1.16.1, this is not present in higher versions - return false; - } - - @Override - public boolean isReplacedDuringPlacement() { - return material.isReplaceable(); - } - - @Override - public boolean isTranslucent() { - return isTranslucent; - } - - @Override - public boolean hasContainer() { - return block instanceof EntityBlock; - } - - @Override - public boolean isTile() { - return block instanceof EntityBlock; - } - - @Override - public CompoundTag getDefaultTile() { - return tile; - } - - @Override - public int getMapColor() { - // rgb field - return material.getColor().col; - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightFaweAdapter.java deleted file mode 100644 index 7cfce755e..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightFaweAdapter.java +++ /dev/null @@ -1,706 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2; - -import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; -import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter; -import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.entity.LazyBaseEntity; -import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IBatchProcessor; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; -import com.fastasyncworldedit.core.util.NbtUtils; -import com.fastasyncworldedit.core.util.TaskManager; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.blocks.TileEntityBlock; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.BukkitWorld; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R2.PaperweightAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.regen.PaperweightRegen; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; -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.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.TreeGenerator; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; -import com.sk89q.worldedit.world.RegenOptions; -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.block.BlockType; -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.item.ItemType; -import com.sk89q.worldedit.world.registry.BlockMaterial; -import io.papermc.lib.PaperLib; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Registry; -import net.minecraft.core.WritableRegistry; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.IntTag; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.util.StringRepresentable; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.DirectionProperty; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.TreeType; -import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_19_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_19_R2.CraftServer; -import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R2.block.CraftBlockState; -import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_19_R2.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_19_R2.util.CraftNamespacedKey; -import org.bukkit.entity.Player; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.OptionalInt; -import java.util.Set; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static net.minecraft.core.registries.Registries.BIOME; - -public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements - IDelegateBukkitImplAdapter { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; - - static { - try { - CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE = ChunkHolder.class.getDeclaredMethod("wasAccessibleSinceLastSave"); - } catch (NoSuchMethodException ignored) { // may not be present in newer paper versions - } - } - - private final PaperweightAdapter parent; - // ------------------------------------------------------------------------ - // Code that may break between versions of Minecraft - // ------------------------------------------------------------------------ - private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil(); - private char[] ibdToStateOrdinal = null; - private int[] ordinalToIbdID = null; - private boolean initialised = false; - private Map>> allBlockProperties = null; - - public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { - this.parent = new PaperweightAdapter(); - } - - @Nullable - private static String getEntityId(Entity entity) { - ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType()); - return resourceLocation == null ? null : resourceLocation.toString(); - } - - private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { - entity.save(compoundTag); - } - - @Override - public BukkitImplAdapter getParent() { - return parent; - } - - private synchronized boolean init() { - if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) { - return false; - } - ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size - ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size - for (int i = 0; i < ibdToStateOrdinal.length; i++) { - BlockState blockState = BlockTypesCache.states[i]; - PaperweightBlockMaterial material = (PaperweightBlockMaterial) blockState.getMaterial(); - int id = Block.BLOCK_STATE_REGISTRY.getId(material.getState()); - char ordinal = blockState.getOrdinalChar(); - ibdToStateOrdinal[id] = ordinal; - ordinalToIbdID[ordinal] = id; - } - Map>> properties = new HashMap<>(); - try { - for (Field field : BlockStateProperties.class.getDeclaredFields()) { - Object obj = field.get(null); - if (!(obj instanceof net.minecraft.world.level.block.state.properties.Property state)) { - continue; - } - Property property; - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - property = new BooleanProperty( - state.getName(), - (List) ImmutableList.copyOf(state.getPossibleValues()) - ); - } else if (state instanceof DirectionProperty) { - property = new DirectionalProperty( - state.getName(), - state - .getPossibleValues() - .stream() - .map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase())) - .collect(Collectors.toList()) - ); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - property = new EnumProperty( - state.getName(), - state - .getPossibleValues() - .stream() - .map(e -> ((StringRepresentable) e).getSerializedName()) - .collect(Collectors.toList()) - ); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - property = new IntegerProperty( - state.getName(), - (List) ImmutableList.copyOf(state.getPossibleValues()) - ); - } else { - throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state - .getClass() - .getSimpleName()); - } - properties.compute(property.getName().toLowerCase(Locale.ROOT), (k, v) -> { - if (v == null) { - v = new ArrayList<>(Collections.singletonList(property)); - } else { - v.add(property); - } - return v; - }); - } - } catch (IllegalAccessException e) { - e.printStackTrace(); - } finally { - allBlockProperties = ImmutableMap.copyOf(properties); - } - initialised = true; - return true; - } - - @Override - public BlockMaterial getMaterial(BlockType blockType) { - Block block = getBlock(blockType); - return new PaperweightBlockMaterial(block); - } - - @Override - public synchronized BlockMaterial getMaterial(BlockState state) { - net.minecraft.world.level.block.state.BlockState blockState = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState(); - return new PaperweightBlockMaterial(blockState.getBlock(), blockState); - } - - public Block getBlock(BlockType blockType) { - return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK) - .get(new ResourceLocation(blockType.getNamespace(), blockType.getResource())); - } - - @Deprecated - @Override - public BlockState getBlock(Location location) { - Preconditions.checkNotNull(location); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - BlockState state = adapt(blockData); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - return state; - } - - @Override - public BaseBlock getFullBlock(final Location location) { - Preconditions.checkNotNull(location); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - BlockState state = adapt(blockData); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - if (state.getBlockType().getMaterial().hasContainer()) { - - // Read the NBT data - BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); - if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); - return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); - } - } - - return state.toBaseBlock(); - } - - @Override - public Set getSupportedSideEffects() { - return SideEffectSet.defaults().getSideEffectsToApply(); - } - - public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) { - CraftChunk craftChunk = (CraftChunk) chunk; - LevelChunk levelChunk = craftChunk.getHandle(); - Level level = levelChunk.getLevel(); - - BlockPos blockPos = new BlockPos(x, y, z); - net.minecraft.world.level.block.state.BlockState blockState = ((PaperweightBlockMaterial) state.getMaterial()).getState(); - LevelChunkSection[] levelChunkSections = levelChunk.getSections(); - int y4 = y >> 4; - LevelChunkSection section = levelChunkSections[y4]; - - net.minecraft.world.level.block.state.BlockState existing; - if (section == null) { - existing = ((PaperweightBlockMaterial) BlockTypes.AIR.getDefaultState().getMaterial()).getState(); - } else { - existing = section.getBlockState(x & 15, y & 15, z & 15); - } - - levelChunk.removeBlockEntity(blockPos); // Force delete the old tile entity - - CompoundBinaryTag compoundTag = state instanceof BaseBlock ? state.getNbt() : null; - if (compoundTag != null || existing instanceof TileEntityBlock) { - level.setBlock(blockPos, blockState, 0); - // remove tile - if (compoundTag != null) { - // We will assume that the tile entity was created for us, - // though we do not do this on the Forge version - BlockEntity blockEntity = level.getBlockEntity(blockPos); - if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(compoundTag); - tag.put("x", IntTag.valueOf(x)); - tag.put("y", IntTag.valueOf(y)); - tag.put("z", IntTag.valueOf(z)); - blockEntity.load(tag); // readTagIntoTileEntity - load data - } - } - } else { - if (existing == blockState) { - return true; - } - levelChunk.setBlockState(blockPos, blockState, false); - } - if (update) { - level.getMinecraftWorld().sendBlockUpdated(blockPos, existing, blockState, 0); - } - return true; - } - - @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightFaweWorldNativeAccess( - this, - new WeakReference<>(((CraftWorld) world).getHandle()) - ); - } - - @Override - public BaseEntity getEntity(org.bukkit.entity.Entity entity) { - Preconditions.checkNotNull(entity); - - CraftEntity craftEntity = ((CraftEntity) entity); - Entity mcEntity = craftEntity.getHandle(); - - String id = getEntityId(mcEntity); - - if (id != null) { - EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); - Supplier saveTag = () -> { - final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); - readEntityIntoTag(mcEntity, minecraftTag); - //add Id for AbstractChangeSet to work - final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); - final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); - tags.put("Id", StringBinaryTag.of(id)); - return CompoundBinaryTag.from(tags); - }; - return new LazyBaseEntity(type, saveTag); - } else { - return null; - } - } - - @Override - public Component getRichBlockName(BlockType blockType) { - return parent.getRichBlockName(blockType); - } - - @Override - public Component getRichItemName(ItemType itemType) { - return parent.getRichItemName(itemType); - } - - @Override - public Component getRichItemName(BaseItemStack itemStack) { - return parent.getRichItemName(itemStack); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockState state) { - PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); - net.minecraft.world.level.block.state.BlockState mcState = material.getCraftBlockData().getState(); - return OptionalInt.of(Block.BLOCK_STATE_REGISTRY.getId(mcState)); - } - - @Override - public BlockState adapt(BlockData blockData) { - CraftBlockData cbd = ((CraftBlockData) blockData); - net.minecraft.world.level.block.state.BlockState ibd = cbd.getState(); - return adapt(ibd); - } - - public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) { - return BlockTypesCache.states[adaptToChar(blockState)]; - } - - public char adaptToChar(net.minecraft.world.level.block.state.BlockState blockState) { - int id = Block.BLOCK_STATE_REGISTRY.getId(blockState); - if (initialised) { - return ibdToStateOrdinal[id]; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - try { - init(); - return ibdToStateOrdinal[id]; - } catch (ArrayIndexOutOfBoundsException e1) { - LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!", - blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1 - ); - return BlockTypesCache.ReservedIDs.AIR; - } - } - } - - public char ibdIDToOrdinal(int id) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - init(); - return ibdToStateOrdinal[id]; - } - } - - @Override - public char[] getIbdToStateOrdinal() { - if (initialised) { - return ibdToStateOrdinal; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal; - } - init(); - return ibdToStateOrdinal; - } - } - - public int ordinalToIbdID(char ordinal) { - if (initialised) { - return ordinalToIbdID[ordinal]; - } - synchronized (this) { - if (initialised) { - return ordinalToIbdID[ordinal]; - } - init(); - return ordinalToIbdID[ordinal]; - } - } - - @Override - public int[] getOrdinalToIbdID() { - if (initialised) { - return ordinalToIbdID; - } - synchronized (this) { - if (initialised) { - return ordinalToIbdID; - } - init(); - return ordinalToIbdID; - } - } - - @Override - public > BlockData adapt(B state) { - PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); - return material.getCraftBlockData(); - } - - @Override - public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); - ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); - if (map != null && wasAccessibleSinceLastSave(map)) { - boolean flag = false; - // PlayerChunk.d players = map.players; - Stream stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag) - */ Stream.empty(); - - ServerPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle(); - stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer) - .forEach(entityPlayer -> { - synchronized (chunkPacket) { - ClientboundLevelChunkWithLightPacket nmsPacket = (ClientboundLevelChunkWithLightPacket) chunkPacket.getNativePacket(); - if (nmsPacket == null) { - nmsPacket = mapUtil.create(this, chunkPacket); - chunkPacket.setNativePacket(nmsPacket); - } - try { - FaweCache.INSTANCE.CHUNK_FLAG.get().set(true); - entityPlayer.connection.send(nmsPacket); - } finally { - FaweCache.INSTANCE.CHUNK_FLAG.get().set(false); - } - } - }); - } - } - - @Override - public Map> getProperties(BlockType blockType) { - return getParent().getProperties(blockType); - } - - @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) { - int internalId = BlockStateIdAccess.getBlockStateId(blockState); - net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); - return blockState1.hasPostProcess( - ((CraftWorld) world).getHandle(), - new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) - ); - } - - @Override - public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { - ItemStack stack = new ItemStack( - DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM) - .get(ResourceLocation.tryParse(baseItemStack.getType().getId())), - baseItemStack.getAmount() - ); - stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()))); - return CraftItemStack.asCraftMirror(stack); - } - - @Override - public boolean generateTree( - TreeGenerator.TreeType treeType, EditSession editSession, BlockVector3 blockVector3, - org.bukkit.World bukkitWorld - ) { - TreeType bukkitType = BukkitWorld.toBukkitTreeType(treeType); - if (bukkitType == TreeType.CHORUS_PLANT) { - blockVector3 = blockVector3.add( - 0, - 1, - 0 - ); // bukkit skips the feature gen which does this offset normally, so we have to add it back - } - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - final BlockVector3 finalBlockVector = blockVector3; - // Sync to main thread to ensure no clashes occur - Map placed = TaskManager.taskManager().sync(() -> { - serverLevel.captureTreeGeneration = true; - serverLevel.captureBlockStates = true; - try { - if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) { - return null; - } - return ImmutableMap.copyOf(serverLevel.capturedBlockStates); - } finally { - serverLevel.captureBlockStates = false; - serverLevel.captureTreeGeneration = false; - serverLevel.capturedBlockStates.clear(); - } - }); - if (placed == null || placed.isEmpty()) { - return false; - } - for (CraftBlockState craftBlockState : placed.values()) { - if (craftBlockState == null || craftBlockState.getType() == Material.AIR) { - continue; - } - editSession.setBlock(craftBlockState.getX(), craftBlockState.getY(), craftBlockState.getZ(), - BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData()) - ); - } - return true; - } - - @Override - public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { - final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); - final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); - weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); - return weStack; - } - - @Override - public Tag toNative(net.minecraft.nbt.Tag foreign) { - return parent.toNative(foreign); - } - - @Override - public net.minecraft.nbt.Tag fromNative(Tag foreign) { - if (foreign instanceof PaperweightLazyCompoundTag) { - return ((PaperweightLazyCompoundTag) foreign).get(); - } - return parent.fromNative(foreign); - } - - @Override - public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { - return new PaperweightRegen(bukkitWorld, region, target, options).regenerate(); - } - - @Override - public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { - return new PaperweightGetBlocks(world, chunkX, chunkZ); - } - - @Override - public int getInternalBiomeId(BiomeType biomeType) { - final Registry registry = MinecraftServer - .getServer() - .registryAccess() - .registryOrThrow(BIOME); - ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.getId()); - Biome biome = registry.get(resourceLocation); - return registry.getId(biome); - } - - @Override - public Iterable getRegisteredBiomes() { - WritableRegistry biomeRegistry = (WritableRegistry) ((CraftServer) Bukkit.getServer()) - .getServer() - .registryAccess() - .registryOrThrow(BIOME); - List keys = biomeRegistry.stream() - .map(biomeRegistry::getKey).filter(Objects::nonNull).toList(); - List namespacedKeys = new ArrayList<>(); - for (ResourceLocation key : keys) { - try { - namespacedKeys.add(CraftNamespacedKey.fromMinecraft(key)); - } catch (IllegalArgumentException e) { - LOGGER.error("Error converting biome key {}", key.toString(), e); - } - } - return namespacedKeys; - } - - @Override - public RelighterFactory getRelighterFactory() { - if (PaperLib.isPaper()) { - return new PaperweightStarlightRelighterFactory(); - } else { - return new NMSRelighterFactory(); - } - } - - @Override - public Map>> getAllProperties() { - if (initialised) { - return allBlockProperties; - } - synchronized (this) { - if (initialised) { - return allBlockProperties; - } - init(); - return allBlockProperties; - } - } - - @Override - public IBatchProcessor getTickingPostProcessor() { - return new PaperweightPostProcessor(); - } - - private boolean wasAccessibleSinceLastSave(ChunkHolder holder) { - if (!PaperLib.isPaper() || !PaperweightPlatformAdapter.POST_CHUNK_REWRITE) { - try { - return (boolean) CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE.invoke(holder); - } catch (IllegalAccessException | InvocationTargetException ignored) { - // fall-through - } - } - // Papers new chunk system has no related replacement - therefor we assume true. - return true; - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightFaweWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightFaweWorldNativeAccess.java deleted file mode 100644 index e5c26aba5..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightFaweWorldNativeAccess.java +++ /dev/null @@ -1,286 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2; - -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.math.IntPair; -import com.fastasyncworldedit.core.util.TaskManager; -import com.fastasyncworldedit.core.util.task.RunnableVal; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.world.block.BlockState; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.LevelChunk; -import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData; -import org.bukkit.event.block.BlockPhysicsEvent; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.util.Collections; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; - -public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess { - - private static final int UPDATE = 1; - private static final int NOTIFY = 2; - private static final Direction[] NEIGHBOUR_ORDER = { - Direction.EAST, - Direction.WEST, - Direction.DOWN, - Direction.UP, - Direction.NORTH, - Direction.SOUTH - }; - private final PaperweightFaweAdapter paperweightFaweAdapter; - private final WeakReference level; - private final AtomicInteger lastTick; - private final Set cachedChanges = new HashSet<>(); - private final Set cachedChunksToSend = new HashSet<>(); - private SideEffectSet sideEffectSet; - - public PaperweightFaweWorldNativeAccess(PaperweightFaweAdapter paperweightFaweAdapter, WeakReference level) { - this.paperweightFaweAdapter = paperweightFaweAdapter; - this.level = level; - // Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging. - // - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway. - this.lastTick = new AtomicInteger(MinecraftServer.currentTick); - } - - private Level getLevel() { - return Objects.requireNonNull(level.get(), "The reference to the world was lost"); - } - - @Override - public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { - this.sideEffectSet = sideEffectSet; - } - - @Override - public LevelChunk getChunk(int x, int z) { - return getLevel().getChunk(x, z); - } - - @Override - public net.minecraft.world.level.block.state.BlockState toNative(BlockState blockState) { - int stateId = paperweightFaweAdapter.ordinalToIbdID(blockState.getOrdinalChar()); - return BlockStateIdAccess.isValidInternalId(stateId) - ? Block.stateById(stateId) - : ((CraftBlockData) BukkitAdapter.adapt(blockState)).getState(); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk levelChunk, BlockPos blockPos) { - return levelChunk.getBlockState(blockPos); - } - - @Nullable - @Override - public synchronized net.minecraft.world.level.block.state.BlockState setBlockState( - LevelChunk levelChunk, BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState blockState - ) { - int currentTick = MinecraftServer.currentTick; - if (Fawe.isMainThread()) { - return levelChunk.setBlockState(blockPos, blockState, - this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE) - ); - } - // Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( ) - cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState)); - cachedChunksToSend.add(new IntPair(levelChunk.bukkitChunk.getX(), levelChunk.bukkitChunk.getZ())); - boolean nextTick = lastTick.get() > currentTick; - if (nextTick || cachedChanges.size() >= 1024) { - if (nextTick) { - lastTick.set(currentTick); - } - flushAsync(nextTick); - } - return blockState; - } - - @Override - public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition( - net.minecraft.world.level.block.state.BlockState blockState, - BlockPos blockPos - ) { - return Block.updateFromNeighbourShapes(blockState, getLevel(), blockPos); - } - - @Override - public BlockPos getPosition(int x, int y, int z) { - return new BlockPos(x, y, z); - } - - @Override - public void updateLightingForBlock(BlockPos blockPos) { - getLevel().getChunkSource().getLightEngine().checkBlock(blockPos); - } - - @Override - public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) { - // We will assume that the tile entity was created for us, - // though we do not do this on the other versions - BlockEntity blockEntity = getLevel().getBlockEntity(blockPos); - if (blockEntity == null) { - return false; - } - net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeBinary(tag); - blockEntity.load((CompoundTag) nativeTag); - return true; - } - - @Override - public void notifyBlockUpdate( - LevelChunk levelChunk, BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { - getLevel().sendBlockUpdated(blockPos, oldState, newState, UPDATE | NOTIFY); - } - } - - @Override - public boolean isChunkTicking(LevelChunk levelChunk) { - return levelChunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); - } - - @Override - public void markBlockChanged(LevelChunk levelChunk, BlockPos blockPos) { - if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { - ((ServerChunkCache) getLevel().getChunkSource()).blockChanged(blockPos); - } - } - - @Override - public void notifyNeighbors( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - Level level = getLevel(); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - level.blockUpdated(blockPos, oldState.getBlock()); - } else { - // When we don't want events, manually run the physics without them. - // Un-nest neighbour updating - for (Direction direction : NEIGHBOUR_ORDER) { - BlockPos shifted = blockPos.relative(direction); - level.getBlockState(shifted).neighborChanged(level, shifted, oldState.getBlock(), blockPos, false); - } - } - if (newState.hasAnalogOutputSignal()) { - level.updateNeighbourForOutputSignal(blockPos, newState.getBlock()); - } - } - - @Override - public void updateNeighbors( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState, - int recursionLimit - ) { - Level level = getLevel(); - // a == updateNeighbors - // b == updateDiagonalNeighbors - oldState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - CraftWorld craftWorld = level.getWorld(); - if (craftWorld != null) { - BlockPhysicsEvent event = new BlockPhysicsEvent( - craftWorld.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()), - CraftBlockData.fromData(newState) - ); - level.getCraftServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - } - } - newState.triggerEvent(level, blockPos, NOTIFY, recursionLimit); - newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); - } - - @Override - public void onBlockStateChange( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - getLevel().onBlockStateChange(blockPos, oldState, newState); - } - - private synchronized void flushAsync(final boolean sendChunks) { - final Set changes = Set.copyOf(cachedChanges); - cachedChanges.clear(); - final Set toSend; - if (sendChunks) { - toSend = Set.copyOf(cachedChunksToSend); - cachedChunksToSend.clear(); - } else { - toSend = Collections.emptySet(); - } - RunnableVal runnableVal = new RunnableVal<>() { - @Override - public void run(Object value) { - changes.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, - sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) - )); - if (!sendChunks) { - return; - } - for (IntPair chunk : toSend) { - PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); - } - } - }; - TaskManager.taskManager().async(() -> TaskManager.taskManager().sync(runnableVal)); - } - - @Override - public synchronized void flush() { - RunnableVal runnableVal = new RunnableVal<>() { - @Override - public void run(Object value) { - cachedChanges.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, - sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) - )); - for (IntPair chunk : cachedChunksToSend) { - PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); - } - } - }; - if (Fawe.isMainThread()) { - runnableVal.run(); - } else { - TaskManager.taskManager().sync(runnableVal); - } - cachedChanges.clear(); - cachedChunksToSend.clear(); - } - - private record CachedChange( - LevelChunk levelChunk, - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState blockState - ) { - - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightGetBlocks.java deleted file mode 100644 index 19452afd3..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightGetBlocks.java +++ /dev/null @@ -1,1170 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2; - -import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; -import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; -import com.fastasyncworldedit.core.math.BitArrayUnstretched; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.fastasyncworldedit.core.queue.implementation.QueueHandler; -import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.collection.AdaptedMap; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.internal.Constants; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.BiomeTypes; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import io.papermc.lib.PaperLib; -import io.papermc.paper.event.block.BeaconDeactivatedEvent; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.IdMap; -import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; -import net.minecraft.nbt.IntTag; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.util.BitStorage; -import net.minecraft.util.ZeroBitStorage; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.entity.BeaconBlockEntity; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.HashMapPalette; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.LinearPalette; -import net.minecraft.world.level.chunk.Palette; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.level.lighting.LevelLightEngine; -import org.apache.logging.log4j.Logger; -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R2.block.CraftBlock; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import javax.annotation.Nonnull; -import java.util.AbstractSet; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.Future; -import java.util.concurrent.Semaphore; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static net.minecraft.core.registries.Registries.BIOME; - -public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private static final Function posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); - private static final Function nmsTile2We = - tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); - private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin - .getInstance() - .getBukkitImplAdapter()); - private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); - private final ServerLevel serverLevel; - private final int chunkX; - private final int chunkZ; - private final int minHeight; - private final int maxHeight; - private final int minSectionPosition; - private final int maxSectionPosition; - private final Registry biomeRegistry; - private final IdMap> biomeHolderIdMap; - private LevelChunkSection[] sections; - private LevelChunk levelChunk; - private DataLayer[] blockLight; - private DataLayer[] skyLight; - private boolean createCopy = false; - private PaperweightGetBlocks_Copy copy = null; - private boolean forceLoadSections = true; - private boolean lightUpdate = false; - - public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { - this(((CraftWorld) world).getHandle(), chunkX, chunkZ); - } - - public PaperweightGetBlocks(ServerLevel serverLevel, int chunkX, int chunkZ) { - super(serverLevel.getMinBuildHeight() >> 4, (serverLevel.getMaxBuildHeight() - 1) >> 4); - this.serverLevel = serverLevel; - this.chunkX = chunkX; - this.chunkZ = chunkZ; - this.minHeight = serverLevel.getMinBuildHeight(); - this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. - this.minSectionPosition = minHeight >> 4; - this.maxSectionPosition = maxHeight >> 4; - this.skyLight = new DataLayer[getSectionCount()]; - this.blockLight = new DataLayer[getSectionCount()]; - this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME); - this.biomeHolderIdMap = biomeRegistry.asHolderIdMap(); - } - - public int getChunkX() { - return chunkX; - } - - public int getChunkZ() { - return chunkZ; - } - - @Override - public boolean isCreateCopy() { - return createCopy; - } - - @Override - public void setCreateCopy(boolean createCopy) { - this.createCopy = createCopy; - } - - @Override - public IChunkGet getCopy() { - return copy; - } - - @Override - public void setLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { - if (light != null) { - lightUpdate = true; - try { - fillLightNibble(light, LightLayer.BLOCK, minSectionPosition, maxSectionPosition); - } catch (Throwable e) { - e.printStackTrace(); - } - } - } - - @Override - public void setSkyLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { - if (light != null) { - lightUpdate = true; - try { - fillLightNibble(light, LightLayer.SKY, minSectionPosition, maxSectionPosition); - } catch (Throwable e) { - e.printStackTrace(); - } - } - } - - @Override - public void setHeightmapToGet(HeightMapType type, int[] data) { - // height + 1 to match server internal - BitArrayUnstretched bitArray = new BitArrayUnstretched(MathMan.log2nlz(getChunk().getHeight() + 1), 256); - bitArray.fromRaw(data); - Heightmap.Types nativeType = Heightmap.Types.valueOf(type.name()); - Heightmap heightMap = getChunk().heightmaps.get(nativeType); - heightMap.setRawData(getChunk(), nativeType, bitArray.getData()); - } - - @Override - public int getMaxY() { - return maxHeight; - } - - @Override - public int getMinY() { - return minHeight; - } - - @Override - public BiomeType getBiomeType(int x, int y, int z) { - LevelChunkSection section = getSections(false)[(y >> 4) - getMinSectionPosition()]; - Holder biomes = section.getNoiseBiome(x >> 2, (y & 15) >> 2, z >> 2); - return PaperweightPlatformAdapter.adapt(biomes, serverLevel); - } - - @Override - public void removeSectionLighting(int layer, boolean sky) { - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.BLOCK).getDataLayerData( - sectionPos); - if (dataLayer != null) { - lightUpdate = true; - synchronized (dataLayer) { - byte[] bytes = dataLayer.getData(); - Arrays.fill(bytes, (byte) 0); - } - } - if (sky) { - SectionPos sectionPos1 = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer1 = serverLevel - .getChunkSource() - .getLightEngine() - .getLayerListener(LightLayer.SKY) - .getDataLayerData(sectionPos1); - if (dataLayer1 != null) { - lightUpdate = true; - synchronized (dataLayer1) { - byte[] bytes = dataLayer1.getData(); - Arrays.fill(bytes, (byte) 0); - } - } - } - } - - @Override - public CompoundTag getTile(int x, int y, int z) { - BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( - chunkX << 4), y, (z & 15) + ( - chunkZ << 4))); - if (blockEntity == null) { - return null; - } - return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)); - } - - @Override - public Map getTiles() { - Map nmsTiles = getChunk().getBlockEntities(); - if (nmsTiles.isEmpty()) { - return Collections.emptyMap(); - } - return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); - } - - @Override - public int getSkyLight(int x, int y, int z) { - int layer = y >> 4; - int alayer = layer - getMinSectionPosition(); - if (skyLight[alayer] == null) { - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = - serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.SKY).getDataLayerData(sectionPos); - // If the server hasn't generated the section's NibbleArray yet, it will be null - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. - Arrays.fill(LAYER_COUNT, (byte) 15); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( - LightLayer.BLOCK, - sectionPos, - dataLayer, - true - ); - } - skyLight[alayer] = dataLayer; - } - return skyLight[alayer].get(x & 15, y & 15, z & 15); - } - - @Override - public int getEmittedLight(int x, int y, int z) { - int layer = y >> 4; - int alayer = layer - getMinSectionPosition(); - if (blockLight[alayer] == null) { - serverLevel.getRawBrightness(new BlockPos(1, 1, 1), 5); - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = serverLevel - .getChunkSource() - .getLightEngine() - .getLayerListener(LightLayer.BLOCK) - .getDataLayerData(sectionPos); - // If the server hasn't generated the section's DataLayer yet, it will be null - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. - Arrays.fill(LAYER_COUNT, (byte) 15); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos, - dataLayer, true - ); - } - blockLight[alayer] = dataLayer; - } - return blockLight[alayer].get(x & 15, y & 15, z & 15); - } - - @Override - public int[] getHeightMap(HeightMapType type) { - long[] longArray = getChunk().heightmaps.get(Heightmap.Types.valueOf(type.name())).getRawData(); - BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256, longArray); - return bitArray.toRaw(new int[256]); - } - - @Override - public CompoundTag getEntity(UUID uuid) { - Entity entity = serverLevel.getEntity(uuid); - if (entity != null) { - org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); - return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); - } - for (CompoundTag tag : getEntities()) { - if (uuid.equals(tag.getUUID())) { - return tag; - } - } - return null; - } - - @Override - public Set getEntities() { - List entities = PaperweightPlatformAdapter.getEntities(getChunk()); - if (entities.isEmpty()) { - return Collections.emptySet(); - } - int size = entities.size(); - return new AbstractSet<>() { - @Override - public int size() { - return size; - } - - @Override - public boolean isEmpty() { - return false; - } - - @Override - public boolean contains(Object get) { - if (!(get instanceof CompoundTag getTag)) { - return false; - } - UUID getUUID = getTag.getUUID(); - for (Entity entity : entities) { - UUID uuid = entity.getUUID(); - if (uuid.equals(getUUID)) { - return true; - } - } - return false; - } - - @Nonnull - @Override - public Iterator iterator() { - Iterable result = entities.stream().map(input -> { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - input.save(tag); - return (CompoundTag) adapter.toNative(tag); - }).collect(Collectors.toList()); - return result.iterator(); - } - }; - } - - private void removeEntity(Entity entity) { - entity.discard(); - } - - public LevelChunk ensureLoaded(ServerLevel nmsWorld, int chunkX, int chunkZ) { - return PaperweightPlatformAdapter.ensureLoaded(nmsWorld, chunkX, chunkZ); - } - - @Override - @SuppressWarnings("rawtypes") - public synchronized > T call(IChunkSet set, Runnable finalizer) { - forceLoadSections = false; - copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; - try { - ServerLevel nmsWorld = serverLevel; - LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); - - // Remove existing tiles. Create a copy so that we can remove blocks - Map chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); - List beacons = null; - if (!chunkTiles.isEmpty()) { - for (Map.Entry entry : chunkTiles.entrySet()) { - final BlockPos pos = entry.getKey(); - final int lx = pos.getX() & 15; - final int ly = pos.getY(); - final int lz = pos.getZ() & 15; - final int layer = ly >> 4; - if (!set.hasSection(layer)) { - continue; - } - - int ordinal = set.getBlock(lx, ly, lz).getOrdinal(); - if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) { - BlockEntity tile = entry.getValue(); - if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) { - if (beacons == null) { - beacons = new ArrayList<>(); - } - beacons.add(tile); - PaperweightPlatformAdapter.removeBeacon(tile, nmsChunk); - continue; - } - nmsChunk.removeBlockEntity(tile.getBlockPos()); - if (createCopy) { - copy.storeTile(tile); - } - } - } - } - final BiomeType[][] biomes = set.getBiomes(); - - int bitMask = 0; - synchronized (nmsChunk) { - LevelChunkSection[] levelChunkSections = nmsChunk.getSections(); - - for (int layerNo = getMinSectionPosition(); layerNo <= getMaxSectionPosition(); layerNo++) { - - int getSectionIndex = layerNo - getMinSectionPosition(); - int setSectionIndex = layerNo - set.getMinSectionPosition(); - - if (!set.hasSection(layerNo)) { - // No blocks, but might be biomes present. Handle this lazily. - if (biomes == null) { - continue; - } - if (layerNo < set.getMinSectionPosition() || layerNo > set.getMaxSectionPosition()) { - continue; - } - if (biomes[setSectionIndex] != null) { - synchronized (super.sectionLocks[getSectionIndex]) { - LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; - if (createCopy && existingSection != null) { - copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); - } - - if (existingSection == null) { - PalettedContainer> biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer( - biomes[setSectionIndex], - biomeHolderIdMap - ); - LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection( - layerNo, - new char[4096], - adapter, - biomeRegistry, - biomeData - ); - if (PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - null, - newSection, - getSectionIndex - )) { - updateGet(nmsChunk, levelChunkSections, newSection, new char[4096], getSectionIndex); - continue; - } else { - existingSection = levelChunkSections[getSectionIndex]; - if (existingSection == null) { - LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - getSectionIndex - ); - continue; - } - } - } else { - setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); - } - } - } - continue; - } - - bitMask |= 1 << getSectionIndex; - - // setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to - // this chunk GET when #updateGet is called. Future dords, please listen this time. - char[] tmp = set.load(layerNo); - char[] setArr = new char[tmp.length]; - System.arraycopy(tmp, 0, setArr, 0, tmp.length); - - // synchronise on internal section to avoid circular locking with a continuing edit if the chunk was - // submitted to keep loaded internal chunks to queue target size. - synchronized (super.sectionLocks[getSectionIndex]) { - - LevelChunkSection newSection; - LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; - // Don't attempt to tick section whilst we're editing - if (existingSection != null) { - PaperweightPlatformAdapter.clearCounts(existingSection); - if (PaperLib.isPaper()) { - existingSection.tickingList.clear(); - } - } - - if (createCopy) { - char[] tmpLoad = loadPrivately(layerNo); - char[] copyArr = new char[4096]; - System.arraycopy(tmpLoad, 0, copyArr, 0, 4096); - copy.storeSection(getSectionIndex, copyArr); - if (biomes != null && existingSection != null) { - copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); - } - } - - if (existingSection == null) { - PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( - biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId( - BiomeTypes.PLAINS)), - PalettedContainer.Strategy.SECTION_BIOMES, - null - ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); - newSection = PaperweightPlatformAdapter.newChunkSection( - layerNo, - setArr, - adapter, - biomeRegistry, - biomeData - ); - if (PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - null, - newSection, - getSectionIndex - )) { - updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); - continue; - } else { - existingSection = levelChunkSections[getSectionIndex]; - if (existingSection == null) { - LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - getSectionIndex - ); - continue; - } - } - } - - //ensure that the server doesn't try to tick the chunksection while we're editing it. (Again) - PaperweightPlatformAdapter.clearCounts(existingSection); - if (PaperLib.isPaper()) { - existingSection.tickingList.clear(); - } - DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); - - // Synchronize to prevent further acquisitions - synchronized (lock) { - lock.acquire(); // Wait until we have the lock - lock.release(); - try { - sectionLock.writeLock().lock(); - if (this.getChunk() != nmsChunk) { - this.levelChunk = nmsChunk; - this.sections = null; - this.reset(); - } else if (existingSection != getSections(false)[getSectionIndex]) { - this.sections[getSectionIndex] = existingSection; - this.reset(); - } else if (!Arrays.equals( - update(getSectionIndex, new char[4096], true), - loadPrivately(layerNo) - )) { - this.reset(layerNo); - /*} else if (lock.isModified()) { - this.reset(layerNo);*/ - } - } finally { - sectionLock.writeLock().unlock(); - } - - PalettedContainer> biomeData = setBiomesToPalettedContainer( - biomes, - setSectionIndex, - existingSection.getBiomes() - ); - - newSection = - PaperweightPlatformAdapter.newChunkSection( - layerNo, - this::loadPrivately, - setArr, - adapter, - biomeRegistry, - biomeData - ); - if (!PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - existingSection, - newSection, - getSectionIndex - )) { - LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - getSectionIndex - ); - } else { - updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); - } - } - } - } - - Map heightMaps = set.getHeightMaps(); - for (Map.Entry entry : heightMaps.entrySet()) { - PaperweightGetBlocks.this.setHeightmapToGet(entry.getKey(), entry.getValue()); - } - PaperweightGetBlocks.this.setLightingToGet( - set.getLight(), - set.getMinSectionPosition(), - set.getMaxSectionPosition() - ); - PaperweightGetBlocks.this.setSkyLightingToGet( - set.getSkyLight(), - set.getMinSectionPosition(), - set.getMaxSectionPosition() - ); - - Runnable[] syncTasks = null; - - int bx = chunkX << 4; - int bz = chunkZ << 4; - - // Call beacon deactivate events here synchronously - // list will be null on spigot, so this is an implicit isPaper check - if (beacons != null && !beacons.isEmpty()) { - final List finalBeacons = beacons; - - syncTasks = new Runnable[4]; - - syncTasks[3] = () -> { - for (BlockEntity beacon : finalBeacons) { - BeaconBlockEntity.playSound(beacon.getLevel(), beacon.getBlockPos(), SoundEvents.BEACON_DEACTIVATE); - new BeaconDeactivatedEvent(CraftBlock.at(beacon.getLevel(), beacon.getBlockPos())).callEvent(); - } - }; - } - - Set entityRemoves = set.getEntityRemoves(); - if (entityRemoves != null && !entityRemoves.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[3]; - } - - syncTasks[2] = () -> { - Set entitiesRemoved = new HashSet<>(); - final List entities = PaperweightPlatformAdapter.getEntities(nmsChunk); - - for (Entity entity : entities) { - UUID uuid = entity.getUUID(); - if (entityRemoves.contains(uuid)) { - if (createCopy) { - copy.storeEntity(entity); - } - removeEntity(entity); - entitiesRemoved.add(uuid); - entityRemoves.remove(uuid); - } - } - if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { - for (UUID uuid : entityRemoves) { - Entity entity = nmsWorld.getEntities().get(uuid); - if (entity != null) { - removeEntity(entity); - } - } - } - // Only save entities that were actually removed to history - set.getEntityRemoves().clear(); - set.getEntityRemoves().addAll(entitiesRemoved); - }; - } - - Set entities = set.getEntities(); - if (entities != null && !entities.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[2]; - } - - syncTasks[1] = () -> { - Iterator iterator = entities.iterator(); - while (iterator.hasNext()) { - final CompoundTag nativeTag = iterator.next(); - final Map entityTagMap = nativeTag.getValue(); - final StringTag idTag = (StringTag) entityTagMap.get("Id"); - final ListTag posTag = (ListTag) entityTagMap.get("Pos"); - final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); - if (idTag == null || posTag == null || rotTag == null) { - LOGGER.error("Unknown entity tag: {}", nativeTag); - continue; - } - final double x = posTag.getDouble(0); - final double y = posTag.getDouble(1); - final double z = posTag.getDouble(2); - final float yaw = rotTag.getFloat(0); - final float pitch = rotTag.getFloat(1); - final String id = idTag.getValue(); - - EntityType type = EntityType.byString(id).orElse(null); - if (type != null) { - Entity entity = type.create(nmsWorld); - if (entity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); - for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - entity.load(tag); - entity.absMoveTo(x, y, z, yaw, pitch); - entity.setUUID(nativeTag.getUUID()); - if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { - LOGGER.warn( - "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", - id, - nmsWorld.getWorld().getName(), - x, - y, - z - ); - // Unsuccessful create should not be saved to history - iterator.remove(); - } - } - } - } - }; - } - - // set tiles - Map tiles = set.getTiles(); - if (tiles != null && !tiles.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[1]; - } - - syncTasks[0] = () -> { - for (final Map.Entry entry : tiles.entrySet()) { - final CompoundTag nativeTag = entry.getValue(); - final BlockVector3 blockHash = entry.getKey(); - final int x = blockHash.getX() + bx; - final int y = blockHash.getY(); - final int z = blockHash.getZ() + bz; - final BlockPos pos = new BlockPos(x, y, z); - - synchronized (nmsWorld) { - BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); - if (tileEntity == null || tileEntity.isRemoved()) { - nmsWorld.removeBlockEntity(pos); - tileEntity = nmsWorld.getBlockEntity(pos); - } - if (tileEntity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); - tag.put("x", IntTag.valueOf(x)); - tag.put("y", IntTag.valueOf(y)); - tag.put("z", IntTag.valueOf(z)); - tileEntity.load(tag); - } - } - } - }; - } - - Runnable callback; - if (bitMask == 0 && biomes == null && !lightUpdate) { - callback = null; - } else { - int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; - boolean finalLightUpdate = lightUpdate; - callback = () -> { - // Set Modified - nmsChunk.setLightCorrect(true); // Set Modified - nmsChunk.mustNotSave = false; - nmsChunk.setUnsaved(true); - // send to player - if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { - this.send(finalMask, finalLightUpdate); - } - if (finalizer != null) { - finalizer.run(); - } - }; - } - if (syncTasks != null) { - QueueHandler queueHandler = Fawe.instance().getQueueHandler(); - Runnable[] finalSyncTasks = syncTasks; - - // Chain the sync tasks and the callback - Callable chain = () -> { - try { - // Run the sync tasks - for (Runnable task : finalSyncTasks) { - if (task != null) { - task.run(); - } - } - if (callback == null) { - if (finalizer != null) { - finalizer.run(); - } - return null; - } else { - return queueHandler.async(callback, null); - } - } catch (Throwable e) { - e.printStackTrace(); - throw e; - } - }; - //noinspection unchecked - required at compile time - return (T) (Future) queueHandler.sync(chain); - } else { - if (callback == null) { - if (finalizer != null) { - finalizer.run(); - } - } else { - callback.run(); - } - } - } - return null; - } catch (Throwable e) { - e.printStackTrace(); - return null; - } finally { - forceLoadSections = true; - } - } - - private void updateGet( - LevelChunk nmsChunk, - LevelChunkSection[] chunkSections, - LevelChunkSection section, - char[] arr, - int layer - ) { - try { - sectionLock.writeLock().lock(); - if (this.getChunk() != nmsChunk) { - this.levelChunk = nmsChunk; - this.sections = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); - this.reset(); - } - if (this.sections == null) { - this.sections = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); - } - if (this.sections[layer] != section) { - // Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords - this.sections[layer] = new LevelChunkSection[]{section}.clone()[0]; - } - } finally { - sectionLock.writeLock().unlock(); - } - this.blocks[layer] = arr; - } - - private char[] loadPrivately(int layer) { - layer -= getMinSectionPosition(); - if (super.sections[layer] != null) { - synchronized (super.sectionLocks[layer]) { - if (super.sections[layer].isFull() && super.blocks[layer] != null) { - char[] blocks = new char[4096]; - System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096); - return blocks; - } - } - } - return PaperweightGetBlocks.this.update(layer, null, true); - } - - @Override - public synchronized void send(int mask, boolean lighting) { - PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); - } - - /** - * Update a given (nullable) data array to the current data stored in the server's chunk, associated with this - * {@link PaperweightPlatformAdapter} instance. Not synchronised to the {@link PaperweightPlatformAdapter} instance as synchronisation - * is handled where necessary in the method, and should otherwise be handled correctly by this method's caller. - * - * @param layer layer index (0 may denote a negative layer in the world, e.g. at y=-32) - * @param data array to be updated/filled with data or null - * @param aggressive if the cached section array should be re-acquired. - * @return the given array to be filled with data, or a new array if null is given. - */ - @Override - @SuppressWarnings("unchecked") - public char[] update(int layer, char[] data, boolean aggressive) { - LevelChunkSection section = getSections(aggressive)[layer]; - // Section is null, return empty array - if (section == null) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - return data; - } - if (data != null && data.length != 4096) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - } - if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - } - Semaphore lock = PaperweightPlatformAdapter.applyLock(section); - synchronized (lock) { - // Efficiently convert ChunkSection to raw data - try { - lock.acquire(); - - final PalettedContainer blocks = section.getStates(); - final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocks); - final BitStorage bits = (BitStorage) PaperweightPlatformAdapter.fieldStorage.get(dataObject); - - if (bits instanceof ZeroBitStorage) { - Arrays.fill(data, adapter.adaptToChar(blocks.get(0, 0, 0))); // get(int) is only public on paper - return data; - } - - final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get(dataObject); - - final int bitsPerEntry = bits.getBits(); - final long[] blockStates = bits.getRaw(); - - new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).toRaw(data); - - int num_palette; - if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { - num_palette = palette.getSize(); - } else { - // The section's palette is the global block palette. - for (int i = 0; i < 4096; i++) { - char paletteVal = data[i]; - char ordinal = adapter.ibdIDToOrdinal(paletteVal); - data[i] = ordinal; - } - return data; - } - - char[] paletteToOrdinal = FaweCache.INSTANCE.PALETTE_TO_BLOCK_CHAR.get(); - try { - if (num_palette != 1) { - for (int i = 0; i < num_palette; i++) { - char ordinal = ordinal(palette.valueFor(i), adapter); - paletteToOrdinal[i] = ordinal; - } - for (int i = 0; i < 4096; i++) { - char paletteVal = data[i]; - char val = paletteToOrdinal[paletteVal]; - if (val == Character.MAX_VALUE) { - val = ordinal(palette.valueFor(i), adapter); - paletteToOrdinal[i] = val; - } - data[i] = val; - } - } else { - char ordinal = ordinal(palette.valueFor(0), adapter); - Arrays.fill(data, ordinal); - } - } finally { - for (int i = 0; i < num_palette; i++) { - paletteToOrdinal[i] = Character.MAX_VALUE; - } - } - return data; - } catch (IllegalAccessException | InterruptedException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } finally { - lock.release(); - } - } - } - - private char ordinal(BlockState ibd, PaperweightFaweAdapter adapter) { - if (ibd == null) { - return BlockTypesCache.ReservedIDs.AIR; - } else { - return adapter.adaptToChar(ibd); - } - } - - public LevelChunkSection[] getSections(boolean force) { - force &= forceLoadSections; - sectionLock.readLock().lock(); - LevelChunkSection[] tmp = sections; - sectionLock.readLock().unlock(); - if (tmp == null || force) { - try { - sectionLock.writeLock().lock(); - tmp = sections; - if (tmp == null || force) { - LevelChunkSection[] chunkSections = getChunk().getSections(); - tmp = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length); - sections = tmp; - } - } finally { - sectionLock.writeLock().unlock(); - } - } - return tmp; - } - - public LevelChunk getChunk() { - LevelChunk levelChunk = this.levelChunk; - if (levelChunk == null) { - synchronized (this) { - levelChunk = this.levelChunk; - if (levelChunk == null) { - this.levelChunk = levelChunk = ensureLoaded(this.serverLevel, chunkX, chunkZ); - } - } - } - return levelChunk; - } - - private void fillLightNibble(char[][] light, LightLayer lightLayer, int minSectionPosition, int maxSectionPosition) { - for (int Y = 0; Y <= maxSectionPosition - minSectionPosition; Y++) { - if (light[Y] == null) { - continue; - } - SectionPos sectionPos = SectionPos.of(levelChunk.getPos(), Y + minSectionPosition); - DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(lightLayer).getDataLayerData( - sectionPos); - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - Arrays.fill(LAYER_COUNT, lightLayer == LightLayer.SKY ? (byte) 15 : (byte) 0); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( - lightLayer, - sectionPos, - dataLayer, - true - ); - } - synchronized (dataLayer) { - for (int x = 0; x < 16; x++) { - for (int y = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { - int i = y << 8 | z << 4 | x; - if (light[Y][i] < 16) { - dataLayer.set(x, y, z, light[Y][i]); - } - } - } - } - } - } - } - - private PalettedContainer> setBiomesToPalettedContainer( - final BiomeType[][] biomes, - final int sectionIndex, - final PalettedContainerRO> data - ) { - PalettedContainer> biomeData; - if (data instanceof PalettedContainer> palettedContainer) { - biomeData = palettedContainer; - } else { - LOGGER.warn( - "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + - "type {} but got {}", - PalettedContainer.class.getSimpleName(), - data.getClass().getSimpleName() - ); - biomeData = data.recreate(); - } - BiomeType[] sectionBiomes; - if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { - return biomeData; - } - for (int y = 0, index = 0; y < 4; y++) { - for (int z = 0; z < 4; z++) { - for (int x = 0; x < 4; x++, index++) { - BiomeType biomeType = sectionBiomes[index]; - if (biomeType == null) { - continue; - } - biomeData.set( - x, - y, - z, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId(biomeType)) - ); - } - } - } - return biomeData; - } - - @Override - public boolean hasSection(int layer) { - layer -= getMinSectionPosition(); - return getSections(false)[layer] != null; - } - - @Override - @SuppressWarnings("unchecked") - public synchronized boolean trim(boolean aggressive) { - skyLight = new DataLayer[getSectionCount()]; - blockLight = new DataLayer[getSectionCount()]; - if (aggressive) { - sectionLock.writeLock().lock(); - sections = null; - levelChunk = null; - sectionLock.writeLock().unlock(); - return super.trim(true); - } else if (sections == null) { - // don't bother trimming if there are no sections stored. - return true; - } else { - for (int i = getMinSectionPosition(); i <= getMaxSectionPosition(); i++) { - int layer = i - getMinSectionPosition(); - if (!hasSection(i) || !super.sections[layer].isFull()) { - continue; - } - LevelChunkSection existing = getSections(true)[layer]; - try { - final PalettedContainer blocksExisting = existing.getStates(); - - final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocksExisting); - final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get( - dataObject); - int paletteSize; - - if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { - paletteSize = palette.getSize(); - } else { - super.trim(false, i); - continue; - } - if (paletteSize == 1) { - //If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks. - continue; - } - super.trim(false, i); - } catch (IllegalAccessException ignored) { - super.trim(false, i); - } - } - return true; - } - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightGetBlocks_Copy.java deleted file mode 100644 index c56de7093..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightGetBlocks_Copy.java +++ /dev/null @@ -1,248 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2; - -import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; -import com.fastasyncworldedit.core.queue.IBlocks; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.math.BlockVector3; -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.BlockTypesCache; -import net.minecraft.core.Holder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import org.apache.logging.log4j.Logger; - -import javax.annotation.Nullable; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Future; - -public class PaperweightGetBlocks_Copy implements IChunkGet { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private final Map tiles = new HashMap<>(); - private final Set entities = new HashSet<>(); - private final char[][] blocks; - private final int minHeight; - private final int maxHeight; - final ServerLevel serverLevel; - final LevelChunk levelChunk; - private PalettedContainer>[] biomes = null; - - protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { - this.levelChunk = levelChunk; - this.serverLevel = levelChunk.level; - this.minHeight = serverLevel.getMinBuildHeight(); - this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. - this.blocks = new char[getSectionCount()][]; - } - - protected void storeTile(BlockEntity blockEntity) { - tiles.put( - BlockVector3.at( - blockEntity.getBlockPos().getX(), - blockEntity.getBlockPos().getY(), - blockEntity.getBlockPos().getZ() - ), - new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)) - ); - } - - @Override - public Map getTiles() { - return tiles; - } - - @Override - @Nullable - public CompoundTag getTile(int x, int y, int z) { - return tiles.get(BlockVector3.at(x, y, z)); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - protected void storeEntity(Entity entity) { - BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - entities.add((CompoundTag) adapter.toNative(compoundTag)); - } - - @Override - public Set getEntities() { - return this.entities; - } - - @Override - public CompoundTag getEntity(UUID uuid) { - for (CompoundTag tag : entities) { - if (uuid.equals(tag.getUUID())) { - return tag; - } - } - return null; - } - - @Override - public boolean isCreateCopy() { - return false; - } - - @Override - public void setCreateCopy(boolean createCopy) { - } - - @Override - public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { - } - - @Override - public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { - } - - @Override - public void setHeightmapToGet(HeightMapType type, int[] data) { - } - - @Override - public int getMaxY() { - return maxHeight; - } - - @Override - public int getMinY() { - return minHeight; - } - - @Override - public int getMaxSectionPosition() { - return maxHeight >> 4; - } - - @Override - public int getMinSectionPosition() { - return minHeight >> 4; - } - - @Override - public BiomeType getBiomeType(int x, int y, int z) { - Holder biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2); - return PaperweightPlatformAdapter.adapt(biome, serverLevel); - } - - @Override - public void removeSectionLighting(int layer, boolean sky) { - } - - @Override - public boolean trim(boolean aggressive, int layer) { - return false; - } - - @Override - public IBlocks reset() { - return null; - } - - @Override - public int getSectionCount() { - return serverLevel.getSectionsCount(); - } - - protected void storeSection(int layer, char[] data) { - blocks[layer] = data; - } - - protected void storeBiomes(int layer, PalettedContainerRO> biomeData) { - if (biomes == null) { - biomes = new PalettedContainer[getSectionCount()]; - } - if (biomeData instanceof PalettedContainer> palettedContainer) { - biomes[layer] = palettedContainer.copy(); - } else { - LOGGER.error( - "Cannot correctly save biomes to history. Expected class type {} but got {}", - PalettedContainer.class.getSimpleName(), - biomeData.getClass().getSimpleName() - ); - } - } - - @Override - public BaseBlock getFullBlock(int x, int y, int z) { - BlockState state = BlockTypesCache.states[get(x, y, z)]; - return state.toBaseBlock(this, x, y, z); - } - - @Override - public boolean hasSection(int layer) { - layer -= getMinSectionPosition(); - return blocks[layer] != null; - } - - @Override - public char[] load(int layer) { - layer -= getMinSectionPosition(); - return blocks[layer]; - } - - @Override - public char[] loadIfPresent(int layer) { - layer -= getMinSectionPosition(); - return blocks[layer]; - } - - @Override - public BlockState getBlock(int x, int y, int z) { - return BlockTypesCache.states[get(x, y, z)]; - } - - @Override - public int getSkyLight(int x, int y, int z) { - return 0; - } - - @Override - public int getEmittedLight(int x, int y, int z) { - return 0; - } - - @Override - public int[] getHeightMap(HeightMapType type) { - return new int[0]; - } - - @Override - public > T call(IChunkSet set, Runnable finalize) { - return null; - } - - public char get(int x, int y, int z) { - final int layer = (y >> 4) - getMinSectionPosition(); - final int index = (y & 15) << 8 | z << 4 | x; - return blocks[layer][index]; - } - - - @Override - public boolean trim(boolean aggressive) { - return false; - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightMapChunkUtil.java b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightMapChunkUtil.java deleted file mode 100644 index c8acc3cd2..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightMapChunkUtil.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2; - -import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; - -//TODO un-very-break-this -public class PaperweightMapChunkUtil extends MapChunkUtil { - - public PaperweightMapChunkUtil() throws NoSuchFieldException { - fieldX = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("TWO_MEGABYTES", "a")); - fieldZ = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("x", "a")); - fieldBitMask = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("z", "b")); - fieldHeightMap = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("heightmaps", "b")); - fieldChunkData = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("chunkData", "c")); - fieldBlockEntities = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("buffer", "c")); - fieldFull = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("blockEntitiesData", "d")); - fieldX.setAccessible(true); - fieldZ.setAccessible(true); - fieldBitMask.setAccessible(true); - fieldHeightMap.setAccessible(true); - fieldChunkData.setAccessible(true); - fieldBlockEntities.setAccessible(true); - fieldFull.setAccessible(true); - } - - @Override - public ClientboundLevelChunkWithLightPacket createPacket() { - // TODO ??? return new ClientboundLevelChunkPacket(); - throw new UnsupportedOperationException(); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightPlatformAdapter.java deleted file mode 100644 index 479df3b1a..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightPlatformAdapter.java +++ /dev/null @@ -1,700 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2; - -import com.destroystokyo.paper.util.maplist.EntityList; -import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; -import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; -import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.math.BitArrayUnstretched; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.ReflectionUtils; -import com.fastasyncworldedit.core.util.TaskManager; -import com.mojang.datafixers.util.Either; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -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.BlockTypesCache; -import io.papermc.lib.PaperLib; -import io.papermc.paper.world.ChunkEntitySlices; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.IdMap; -import net.minecraft.core.Registry; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.level.TicketType; -import net.minecraft.util.BitStorage; -import net.minecraft.util.ExceptionCollector; -import net.minecraft.util.SimpleBitStorage; -import net.minecraft.util.ThreadingDetector; -import net.minecraft.util.Unit; -import net.minecraft.util.ZeroBitStorage; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.GlobalPalette; -import net.minecraft.world.level.chunk.HashMapPalette; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.LinearPalette; -import net.minecraft.world.level.chunk.Palette; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.SingleValuePalette; -import net.minecraft.world.level.entity.PersistentEntitySectionManager; -import org.bukkit.craftbukkit.v1_19_R2.CraftChunk; -import sun.misc.Unsafe; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Semaphore; -import java.util.function.Function; - -import static net.minecraft.core.registries.Registries.BIOME; - -public final class PaperweightPlatformAdapter extends NMSAdapter { - - public static final Field fieldData; - - public static final Constructor dataConstructor; - - public static final Field fieldStorage; - public static final Field fieldPalette; - - private static final Field fieldTickingFluidCount; - private static final Field fieldTickingBlockCount; - private static final Field fieldNonEmptyBlockCount; - - private static final MethodHandle methodGetVisibleChunk; - - private static final int CHUNKSECTION_BASE; - private static final int CHUNKSECTION_SHIFT; - - private static final Field fieldThreadingDetector; - private static final long fieldThreadingDetectorOffset; - - private static final Field fieldLock; - private static final long fieldLockOffset; - - private static final MethodHandle methodRemoveGameEventListener; - private static final MethodHandle methodremoveTickingBlockEntity; - - private static final Field fieldRemove; - - static final boolean POST_CHUNK_REWRITE; - private static Method PAPER_CHUNK_GEN_ALL_ENTITIES; - private static Field LEVEL_CHUNK_ENTITIES; - private static Field SERVER_LEVEL_ENTITY_MANAGER; - - static { - try { - fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d")); - fieldData.setAccessible(true); - - Class dataClazz = fieldData.getType(); - dataConstructor = dataClazz.getDeclaredConstructors()[0]; - dataConstructor.setAccessible(true); - - fieldStorage = dataClazz.getDeclaredField(Refraction.pickName("storage", "b")); - fieldStorage.setAccessible(true); - fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c")); - fieldPalette.setAccessible(true); - - fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "h")); - fieldTickingFluidCount.setAccessible(true); - fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g")); - fieldTickingBlockCount.setAccessible(true); - fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f")); - fieldNonEmptyBlockCount.setAccessible(true); - - Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( - "getVisibleChunkIfPresent", - "b" - ), long.class); - getVisibleChunkIfPresent.setAccessible(true); - methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent); - - Unsafe unsafe = ReflectionUtils.getUnsafe(); - if (!PaperLib.isPaper()) { - fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); - fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector); - - fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); - fieldLockOffset = unsafe.objectFieldOffset(fieldLock); - } else { - // in paper, the used methods are synchronized properly - fieldThreadingDetector = null; - fieldThreadingDetectorOffset = -1; - - fieldLock = null; - fieldLockOffset = -1; - } - - Method removeGameEventListener = LevelChunk.class.getDeclaredMethod( - Refraction.pickName("removeGameEventListener", "a"), - BlockEntity.class, - ServerLevel.class - ); - removeGameEventListener.setAccessible(true); - methodRemoveGameEventListener = MethodHandles.lookup().unreflect(removeGameEventListener); - - Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod( - Refraction.pickName( - "removeBlockEntityTicker", - "l" - ), BlockPos.class - ); - removeBlockEntityTicker.setAccessible(true); - methodremoveTickingBlockEntity = MethodHandles.lookup().unreflect(removeBlockEntityTicker); - - fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p")); - fieldRemove.setAccessible(true); - - CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class); - int scale = unsafe.arrayIndexScale(LevelChunkSection[].class); - if ((scale & (scale - 1)) != 0) { - throw new Error("data type scale not a power of two"); - } - CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale); - boolean chunkRewrite; - try { - ServerLevel.class.getDeclaredMethod("getEntityLookup"); - chunkRewrite = true; - PAPER_CHUNK_GEN_ALL_ENTITIES = ChunkEntitySlices.class.getDeclaredMethod("getAllEntities"); - PAPER_CHUNK_GEN_ALL_ENTITIES.setAccessible(true); - } catch (NoSuchMethodException ignored) { - chunkRewrite = false; - } - try { - // Paper - Pre-Chunk-Update - LEVEL_CHUNK_ENTITIES = LevelChunk.class.getDeclaredField("entities"); - LEVEL_CHUNK_ENTITIES.setAccessible(true); - } catch (NoSuchFieldException ignored) { - } - try { - // Non-Paper - SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "P")); - SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true); - } catch (NoSuchFieldException ignored) { - } - POST_CHUNK_REWRITE = chunkRewrite; - } catch (RuntimeException e) { - throw e; - } catch (Throwable rethrow) { - rethrow.printStackTrace(); - throw new RuntimeException(rethrow); - } - } - - static boolean setSectionAtomic( - LevelChunkSection[] sections, - LevelChunkSection expected, - LevelChunkSection value, - int layer - ) { - long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE; - if (layer >= 0 && layer < sections.length) { - return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value); - } - return false; - } - - // There is no point in having a functional semaphore for paper servers. - private static final ThreadLocal SEMAPHORE_THREAD_LOCAL = - ThreadLocal.withInitial(() -> new DelegateSemaphore(1, null)); - - static DelegateSemaphore applyLock(LevelChunkSection section) { - if (PaperLib.isPaper()) { - return SEMAPHORE_THREAD_LOCAL.get(); - } - try { - synchronized (section) { - Unsafe unsafe = ReflectionUtils.getUnsafe(); - PalettedContainer blocks = section.getStates(); - ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject( - blocks, - fieldThreadingDetectorOffset - ); - synchronized (currentThreadingDetector) { - Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset); - if (currentLock instanceof DelegateSemaphore delegateSemaphore) { - return delegateSemaphore; - } - DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); - unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock); - return newLock; - } - } - } catch (Throwable e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - } - - public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) { - if (!PaperLib.isPaper()) { - LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false); - if (nmsChunk != null) { - return nmsChunk; - } - if (Fawe.isMainThread()) { - return serverLevel.getChunk(chunkX, chunkZ); - } - } else { - LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ); - if (nmsChunk != null) { - addTicket(serverLevel, chunkX, chunkZ); - return nmsChunk; - } - nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ); - if (nmsChunk != null) { - addTicket(serverLevel, chunkX, chunkZ); - return nmsChunk; - } - // Avoid "async" methods from the main thread. - if (Fawe.isMainThread()) { - return serverLevel.getChunk(chunkX, chunkZ); - } - CompletableFuture future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true); - try { - CraftChunk chunk = (CraftChunk) future.get(); - return chunk.getHandle(); - } catch (Throwable e) { - e.printStackTrace(); - } - } - return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)); - } - - private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) { - // Ensure chunk is definitely loaded before applying a ticket - io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel - .getChunkSource() - .addRegionTicket(TicketType.PLUGIN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE)); - } - - public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) { - ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap; - try { - return (ChunkHolder) methodGetVisibleChunk.invoke(chunkMap, ChunkPos.asLong(chunkX, chunkZ)); - } catch (Throwable thr) { - throw new RuntimeException(thr); - } - } - - @SuppressWarnings("deprecation") - public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) { - ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); - if (chunkHolder == null) { - return; - } - ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ); - LevelChunk levelChunk; - if (PaperLib.isPaper()) { - // getChunkAtIfLoadedImmediately is paper only - levelChunk = nmsWorld - .getChunkSource() - .getChunkAtIfLoadedImmediately(chunkX, chunkZ); - } else { - levelChunk = ((Optional) ((Either) chunkHolder - .getTickingChunkFuture() // method is not present with new paper chunk system - .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left()) - .orElse(null); - } - if (levelChunk == null) { - return; - } - TaskManager.taskManager().task(() -> { - ClientboundLevelChunkWithLightPacket packet; - if (PaperLib.isPaper()) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - true, - false // last false is to not bother with x-ray - ); - } else { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - true - ); - } - nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); - }); - } - - private static List nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) { - return serverLevel.getChunkSource().chunkMap.getPlayers(coordIntPair, false); - } - - /* - NMS conversion - */ - public static LevelChunkSection newChunkSection( - final int layer, - final char[] blocks, - CachedBukkitAdapter adapter, - Registry biomeRegistry, - @Nullable PalettedContainer> biomes - ) { - return newChunkSection(layer, null, blocks, adapter, biomeRegistry, biomes); - } - - public static LevelChunkSection newChunkSection( - final int layer, - final Function get, - char[] set, - CachedBukkitAdapter adapter, - Registry biomeRegistry, - @Nullable PalettedContainer> biomes - ) { - if (set == null) { - return newChunkSection(layer, biomeRegistry, biomes); - } - final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); - final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); - final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get(); - final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get(); - try { - int num_palette; - if (get == null) { - num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter, null); - } else { - num_palette = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, get, set, adapter, null); - } - - int bitsPerEntry = MathMan.log2nlz(num_palette - 1); - if (bitsPerEntry > 0 && bitsPerEntry < 5) { - bitsPerEntry = 4; - } else if (bitsPerEntry > 8) { - bitsPerEntry = MathMan.log2nlz(Block.BLOCK_STATE_REGISTRY.size() - 1); - } - - int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes - final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); - final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong); - - if (num_palette == 1) { - for (int i = 0; i < blockBitArrayEnd; i++) { - blockStates[i] = 0; - } - } else { - final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntryNonZero, 4096, blockStates); - bitArray.fromRaw(blocksCopy); - } - - final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd); - final BitStorage nmsBits; - if (bitsPerEntry == 0) { - nmsBits = new ZeroBitStorage(4096); - } else { - nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits); - } - List palette; - if (bitsPerEntry < 9) { - palette = new ArrayList<>(); - for (int i = 0; i < num_palette; i++) { - int ordinal = paletteToBlock[i]; - blockToPalette[ordinal] = Integer.MAX_VALUE; - final BlockState state = BlockTypesCache.states[ordinal]; - palette.add(((PaperweightBlockMaterial) state.getMaterial()).getState()); - } - } else { - palette = List.of(); - } - - // Create palette with data - @SuppressWarnings("deprecation") // constructor is deprecated on paper, but needed to keep compatibility with spigot - final PalettedContainer blockStatePalettedContainer = - new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, - PalettedContainer.Strategy.SECTION_STATES, - PalettedContainer.Strategy.SECTION_STATES.getConfiguration(Block.BLOCK_STATE_REGISTRY, bitsPerEntry), - nmsBits, - palette - ); - if (biomes == null) { - IdMap> biomeHolderIdMap = biomeRegistry.asHolderIdMap(); - biomes = new PalettedContainer<>( - biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId( - BiomeTypes.PLAINS)), - PalettedContainer.Strategy.SECTION_BIOMES, - null - ); - } - - return new LevelChunkSection(layer, blockStatePalettedContainer, biomes); - } catch (final Throwable e) { - throw e; - } finally { - Arrays.fill(blockToPalette, Integer.MAX_VALUE); - Arrays.fill(paletteToBlock, Integer.MAX_VALUE); - Arrays.fill(blockStates, 0); - Arrays.fill(blocksCopy, 0); - } - } - - @SuppressWarnings("deprecation") // Only deprecated in paper - private static LevelChunkSection newChunkSection( - int layer, - Registry biomeRegistry, - @Nullable PalettedContainer> biomes - ) { - if (biomes == null) { - return new LevelChunkSection(layer, biomeRegistry); - } - PalettedContainer dataPaletteBlocks = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, - Blocks.AIR.defaultBlockState(), - PalettedContainer.Strategy.SECTION_STATES, - null - ); - return new LevelChunkSection(layer, dataPaletteBlocks, biomes); - } - - /** - * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. - */ - public static PalettedContainer> getBiomePalettedContainer( - BiomeType[] biomes, - IdMap> biomeRegistry - ) { - if (biomes == null) { - return null; - } - BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); - // Don't stream this as typically will see 1-4 biomes; stream overhead is large for the small length - Map> palette = new HashMap<>(); - for (BiomeType biomeType : new LinkedList<>(Arrays.asList(biomes))) { - Holder biome; - if (biomeType == null) { - biome = biomeRegistry.byId(adapter.getInternalBiomeId(BiomeTypes.PLAINS)); - } else { - biome = biomeRegistry.byId(adapter.getInternalBiomeId(biomeType)); - } - palette.put(biomeType, biome); - } - int biomeCount = palette.size(); - int bitsPerEntry = MathMan.log2nlz(biomeCount - 1); - Object configuration = PalettedContainer.Strategy.SECTION_STATES.getConfiguration( - new FakeIdMapBiome(biomeCount), - bitsPerEntry - ); - if (bitsPerEntry > 3) { - bitsPerEntry = MathMan.log2nlz(biomeRegistry.size() - 1); - } - PalettedContainer> biomePalettedContainer = new PalettedContainer<>( - biomeRegistry, - biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), - PalettedContainer.Strategy.SECTION_BIOMES, - null - ); - - final Palette> biomePalette; - if (bitsPerEntry == 0) { - biomePalette = new SingleValuePalette<>( - biomePalettedContainer.registry, - biomePalettedContainer, - new ArrayList<>(palette.values()) // Must be modifiable - ); - } else if (bitsPerEntry == 4) { - biomePalette = LinearPalette.create( - 4, - biomePalettedContainer.registry, - biomePalettedContainer, - new ArrayList<>(palette.values()) // Must be modifiable - ); - } else if (bitsPerEntry < 9) { - biomePalette = HashMapPalette.create( - bitsPerEntry, - biomePalettedContainer.registry, - biomePalettedContainer, - new ArrayList<>(palette.values()) // Must be modifiable - ); - } else { - biomePalette = GlobalPalette.create( - bitsPerEntry, - biomePalettedContainer.registry, - biomePalettedContainer, - null // unused - ); - } - - int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes - final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); - final int arrayLength = MathMan.ceilZero(64f / blocksPerLong); - - - BitStorage bitStorage = bitsPerEntry == 0 ? new ZeroBitStorage(64) : new SimpleBitStorage( - bitsPerEntry, - 64, - new long[arrayLength] - ); - - try { - Object data = dataConstructor.newInstance(configuration, bitStorage, biomePalette); - fieldData.set(biomePalettedContainer, data); - int index = 0; - for (int y = 0; y < 4; y++) { - for (int z = 0; z < 4; z++) { - for (int x = 0; x < 4; x++, index++) { - BiomeType biomeType = biomes[index]; - if (biomeType == null) { - continue; - } - Holder biome = biomeRegistry.byId(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId(biomeType)); - if (biome == null) { - continue; - } - biomePalettedContainer.set(x, y, z, biome); - } - } - } - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException(e); - } - return biomePalettedContainer; - } - - public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException { - fieldTickingFluidCount.setShort(section, (short) 0); - fieldTickingBlockCount.setShort(section, (short) 0); - } - - public static BiomeType adapt(Holder biome, LevelAccessor levelAccessor) { - final Registry biomeRegistry = levelAccessor.registryAccess().registryOrThrow(BIOME); - if (biomeRegistry.getKey(biome.value()) == null) { - return biomeRegistry.asHolderIdMap().getId(biome) == -1 ? BiomeTypes.OCEAN - : null; - } - return BiomeTypes.get(biome.unwrapKey().orElseThrow().location().toString()); - } - - static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { - try { - if (levelChunk.loaded || levelChunk.level.isClientSide()) { - BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos()); - if (blockEntity != null) { - if (!levelChunk.level.isClientSide) { - methodRemoveGameEventListener.invoke(levelChunk, beacon, levelChunk.level); - } - fieldRemove.set(beacon, true); - } - } - methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos()); - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - } - - static List getEntities(LevelChunk chunk) { - ExceptionCollector collector = new ExceptionCollector<>(); - if (PaperLib.isPaper()) { - if (POST_CHUNK_REWRITE) { - try { - //noinspection unchecked - return (List) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level.getEntityLookup().getChunk(chunk.locX, chunk.locZ)); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=true]", e); - } - } - try { - EntityList entityList = (EntityList) LEVEL_CHUNK_ENTITIES.get(chunk); - return List.of(entityList.getRawData()); - } catch (IllegalAccessException e) { - collector.add(new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=false]", e)); - // fall through - } - } - try { - //noinspection unchecked - return ((PersistentEntitySectionManager) (SERVER_LEVEL_ENTITY_MANAGER.get(chunk.level))).getEntities(chunk.getPos()); - } catch (IllegalAccessException e) { - collector.add(new RuntimeException("Failed to lookup entities [PAPER=false]", e)); - } - collector.throwIfPresent(); - return List.of(); - } - - record FakeIdMapBlock(int size) implements IdMap { - - @Override - public int getId(final net.minecraft.world.level.block.state.BlockState entry) { - return 0; - } - - @Nullable - @Override - public net.minecraft.world.level.block.state.BlockState byId(final int index) { - return null; - } - - @Nonnull - @Override - public Iterator iterator() { - return Collections.emptyIterator(); - } - - } - - record FakeIdMapBiome(int size) implements IdMap { - - @Override - public int getId(final Biome entry) { - return 0; - } - - @Nullable - @Override - public Biome byId(final int index) { - return null; - } - - @Nonnull - @Override - public Iterator iterator() { - return Collections.emptyIterator(); - } - - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightPostProcessor.java b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightPostProcessor.java deleted file mode 100644 index a3f016f42..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightPostProcessor.java +++ /dev/null @@ -1,175 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2; - -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.ProcessorScope; -import com.fastasyncworldedit.core.queue.IBatchProcessor; -import com.fastasyncworldedit.core.queue.IChunk; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.fastasyncworldedit.core.registry.state.PropertyKey; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.Fluids; - -import javax.annotation.Nullable; - -public class PaperweightPostProcessor implements IBatchProcessor { - - @Override - public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) { - return set; - } - - @SuppressWarnings("deprecation") - @Override - public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) { - boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS; - // The PostProcessor shouldn't be added, but just in case - if (!tickFluid) { - return; - } - PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet; - layer: - for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) { - char[] set = iChunkSet.loadIfPresent(layer); - if (set == null) { - // No edit means no need to process - continue; - } - char[] get = null; - for (int i = 0; i < 4096; i++) { - char ordinal = set[i]; - char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__; - boolean fromGet = false; // Used for liquids - if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { - if (get == null) { - get = getBlocks.load(layer); - } - // If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't - // actually being set - if (get == null) { - continue layer; - } - fromGet = true; - ordinal = replacedOrdinal = get[i]; - } - if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { - continue; - } else if (!fromGet) { // if fromGet, don't do the same again - if (get == null) { - get = getBlocks.load(layer); - } - replacedOrdinal = get[i]; - } - boolean ticking = BlockTypesCache.ticking[ordinal]; - boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal]; - boolean replacedWasLiquid = false; - BlockState replacedState = null; - if (!ticking) { - // If the block being replaced was not ticking, it cannot be a liquid - if (!replacedWasTicking) { - continue; - } - // If the block being replaced is not fluid, we do not need to worry - if (!(replacedWasLiquid = - (replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) { - continue; - } - } - BlockState state = BlockState.getFromOrdinal(ordinal); - boolean liquid = state.getMaterial().isLiquid(); - int x = i & 15; - int y = (i >> 8) & 15; - int z = (i >> 4) & 15; - BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z); - if (liquid || replacedWasLiquid) { - if (liquid) { - addFluid(getBlocks.serverLevel, state, position); - continue; - } - // If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this - // may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up - // being ticked anyway. We only need it to be "hit" once. - if (!wasAdjacentToWater(get, set, i, x, y, z)) { - continue; - } - addFluid(getBlocks.serverLevel, replacedState, position); - } - } - } - } - - @Nullable - @Override - public Extent construct(final Extent child) { - throw new UnsupportedOperationException("Processing only"); - } - - @Override - public ProcessorScope getScope() { - return ProcessorScope.READING_SET_BLOCKS; - } - - private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) { - if (set == null || get == null) { - return false; - } - char ordinal; - char reserved = BlockTypesCache.ReservedIDs.__RESERVED__; - if (x > 0 && set[i - 1] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) { - return true; - } - } - if (x < 15 && set[i + 1] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) { - return true; - } - } - if (z > 0 && set[i - 16] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) { - return true; - } - } - if (z < 15 && set[i + 16] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) { - return true; - } - } - if (y > 0 && set[i - 256] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) { - return true; - } - } - if (y < 15 && set[i + 256] != reserved) { - return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal); - } - return false; - } - - @SuppressWarnings("deprecation") - private boolean isFluid(char ordinal) { - return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid(); - } - - @SuppressWarnings("deprecation") - private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) { - Fluid type; - if (replacedState.getBlockType() == BlockTypes.LAVA) { - type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA; - } else { - type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER; - } - serverLevel.scheduleTick( - position, - type, - type.getTickDelay(serverLevel) - ); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightStarlightRelighter.java deleted file mode 100644 index 642250aa0..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightStarlightRelighter.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2; - -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter; -import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; -import com.fastasyncworldedit.core.queue.IQueueChunk; -import com.fastasyncworldedit.core.queue.IQueueExtent; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.TaskManager; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -import it.unimi.dsi.fastutil.longs.LongArraySet; -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.longs.LongSet; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.TicketType; -import net.minecraft.util.Unit; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.chunk.ChunkStatus; -import org.apache.logging.log4j.Logger; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Consumer; -import java.util.function.IntConsumer; - -public class PaperweightStarlightRelighter implements Relighter { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - private static final int CHUNKS_PER_BATCH = 1024; // 32 * 32 - private static final int CHUNKS_PER_BATCH_SQRT_LOG2 = 5; // for shifting - - private static final TicketType FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); - private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkStatus.getDistance(ChunkStatus.LIGHT); - - - private final ServerLevel serverLevel; - private final ReentrantLock lock = new ReentrantLock(); - private final Long2ObjectLinkedOpenHashMap regions = new Long2ObjectLinkedOpenHashMap<>(); - private final ReentrantLock areaLock = new ReentrantLock(); - private final NMSRelighter delegate; - - @SuppressWarnings("rawtypes") - public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { - this.serverLevel = serverLevel; - this.delegate = new NMSRelighter(queue); - } - - @Override - public boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask) { - areaLock.lock(); - try { - long key = MathMan.pairInt(cx >> CHUNKS_PER_BATCH_SQRT_LOG2, cz >> CHUNKS_PER_BATCH_SQRT_LOG2); - // TODO probably submit here already if chunks.size == CHUNKS_PER_BATCH? - LongSet chunks = this.regions.computeIfAbsent(key, k -> new LongArraySet(CHUNKS_PER_BATCH >> 2)); - chunks.add(ChunkPos.asLong(cx, cz)); - } finally { - areaLock.unlock(); - } - return true; - } - - @Override - public void addLightUpdate(int x, int y, int z) { - delegate.addLightUpdate(x, y, z); - } - - /* - * This method is called "recursively", iterating and removing elements - * from the regions linked map. This way, chunks are loaded in batches to avoid - * OOMEs. - */ - @Override - public void fixLightingSafe(boolean sky) { - this.areaLock.lock(); - try { - if (regions.isEmpty()) { - return; - } - LongSet first = regions.removeFirst(); - fixLighting(first, () -> fixLightingSafe(true)); - } finally { - this.areaLock.unlock(); - } - } - - /* - * Processes a set of chunks and runs an action afterwards. - * The action is run async, the chunks are partly processed on the main thread - * (as required by the server). - */ - private void fixLighting(LongSet chunks, Runnable andThen) { - // convert from long keys to ChunkPos - Set coords = new HashSet<>(); - LongIterator iterator = chunks.iterator(); - while (iterator.hasNext()) { - coords.add(new ChunkPos(iterator.nextLong())); - } - TaskManager.taskManager().task(() -> { - // trigger chunk load and apply ticket on main thread - List> futures = new ArrayList<>(); - for (ChunkPos pos : coords) { - futures.add(serverLevel.getWorld().getChunkAtAsync(pos.x, pos.z) - .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( - FAWE_TICKET, - pos, - LIGHT_LEVEL, - Unit.INSTANCE - )) - ); - } - // collect futures and trigger relight once all chunks are loaded - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(v -> - invokeRelight( - coords, - c -> { - }, // no callback for single chunks required - i -> { - if (i != coords.size()) { - LOGGER.warn("Processed {} chunks instead of {}", i, coords.size()); - } - // post process chunks on main thread - TaskManager.taskManager().task(() -> postProcessChunks(coords)); - // call callback on our own threads - TaskManager.taskManager().async(andThen); - } - ) - ); - }); - } - - private void invokeRelight( - Set coords, - Consumer chunkCallback, - IntConsumer processCallback - ) { - try { - serverLevel.getChunkSource().getLightEngine().relight(coords, chunkCallback, processCallback); - } catch (Exception e) { - LOGGER.error("Error occurred on relighting", e); - } - } - - /* - * Allow the server to unload the chunks again. - * Also, if chunk packets are sent delayed, we need to do that here - */ - private void postProcessChunks(Set coords) { - boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING; - for (ChunkPos pos : coords) { - int x = pos.x; - int z = pos.z; - if (delay) { // we still need to send the block changes of that chunk - PaperweightPlatformAdapter.sendChunk(serverLevel, x, z, false); - } - serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE); - } - } - - @Override - public void clear() { - - } - - @Override - public void removeLighting() { - this.delegate.removeLighting(); - } - - @Override - public void fixBlockLighting() { - fixLightingSafe(true); - } - - @Override - public void fixSkyLighting() { - fixLightingSafe(true); - } - - @Override - public boolean isEmpty() { - return true; - } - - @Override - public ReentrantLock getLock() { - return this.lock; - } - - @Override - public boolean isFinished() { - return false; - } - - @Override - public void close() throws Exception { - fixLightingSafe(true); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightStarlightRelighterFactory.java deleted file mode 100644 index 3741b552c..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/PaperweightStarlightRelighterFactory.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2; - -import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; -import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; -import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; -import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IQueueChunk; -import com.fastasyncworldedit.core.queue.IQueueExtent; -import com.sk89q.worldedit.world.World; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; - -import javax.annotation.Nonnull; - -public class PaperweightStarlightRelighterFactory implements RelighterFactory { - - @Override - public @Nonnull - @SuppressWarnings("rawtypes") - Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { - org.bukkit.World w = Bukkit.getWorld(world.getName()); - if (w == null) { - return NullRelighter.INSTANCE; - } - return new PaperweightStarlightRelighter(((CraftWorld) w).getHandle(), queue); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/nbt/PaperweightLazyCompoundTag.java deleted file mode 100644 index 9ff3c1f61..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/nbt/PaperweightLazyCompoundTag.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.nbt; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.LazyCompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import net.minecraft.nbt.NumericTag; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Supplier; - -public class PaperweightLazyCompoundTag extends LazyCompoundTag { - - private final Supplier compoundTagSupplier; - private CompoundTag compoundTag; - - public PaperweightLazyCompoundTag(Supplier compoundTagSupplier) { - super(new HashMap<>()); - this.compoundTagSupplier = compoundTagSupplier; - } - - public PaperweightLazyCompoundTag(net.minecraft.nbt.CompoundTag compoundTag) { - this(() -> compoundTag); - } - - public net.minecraft.nbt.CompoundTag get() { - return compoundTagSupplier.get(); - } - - @Override - @SuppressWarnings("unchecked") - public Map getValue() { - if (compoundTag == null) { - compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); - } - return compoundTag.getValue(); - } - - @Override - public CompoundBinaryTag asBinaryTag() { - getValue(); - return compoundTag.asBinaryTag(); - } - - public boolean containsKey(String key) { - return compoundTagSupplier.get().contains(key); - } - - public byte[] getByteArray(String key) { - return compoundTagSupplier.get().getByteArray(key); - } - - public byte getByte(String key) { - return compoundTagSupplier.get().getByte(key); - } - - public double getDouble(String key) { - return compoundTagSupplier.get().getDouble(key); - } - - public double asDouble(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsDouble(); - } - return 0; - } - - public float getFloat(String key) { - return compoundTagSupplier.get().getFloat(key); - } - - public int[] getIntArray(String key) { - return compoundTagSupplier.get().getIntArray(key); - } - - public int getInt(String key) { - return compoundTagSupplier.get().getInt(key); - } - - public int asInt(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsInt(); - } - return 0; - } - - @SuppressWarnings("unchecked") - public List getList(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof net.minecraft.nbt.ListTag nbtList) { - ArrayList list = new ArrayList<>(); - for (net.minecraft.nbt.Tag elem : nbtList) { - if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { - list.add(new PaperweightLazyCompoundTag(compoundTag)); - } else { - list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem)); - } - } - return list; - } - return Collections.emptyList(); - } - - @SuppressWarnings("unchecked") - public ListTag getListTag(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof net.minecraft.nbt.ListTag) { - return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag); - } - return new ListTag(StringTag.class, Collections.emptyList()); - } - - @SuppressWarnings("unchecked") - public List getList(String key, Class listType) { - ListTag listTag = getListTag(key); - if (listTag.getType().equals(listType)) { - return (List) listTag.getValue(); - } else { - return Collections.emptyList(); - } - } - - public long[] getLongArray(String key) { - return compoundTagSupplier.get().getLongArray(key); - } - - public long getLong(String key) { - return compoundTagSupplier.get().getLong(key); - } - - public long asLong(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsLong(); - } - return 0; - } - - public short getShort(String key) { - return compoundTagSupplier.get().getShort(key); - } - - public String getString(String key) { - return compoundTagSupplier.get().getString(key); - } - - @Override - public String toString() { - return compoundTagSupplier.get().toString(); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/regen/PaperweightRegen.java deleted file mode 100644 index 74dccf63b..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R2/regen/PaperweightRegen.java +++ /dev/null @@ -1,594 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.regen; - -import com.fastasyncworldedit.bukkit.adapter.Regenerator; -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.queue.IChunkCache; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.util.ReflectionUtils; -import com.fastasyncworldedit.core.util.TaskManager; -import com.google.common.collect.ImmutableList; -import com.mojang.datafixers.util.Either; -import com.mojang.serialization.Lifecycle; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.PaperweightGetBlocks; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.world.RegenOptions; -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.server.level.progress.ChunkProgressListener; -import net.minecraft.util.thread.ProcessorHandle; -import net.minecraft.util.thread.ProcessorMailbox; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.LevelSettings; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.BiomeSource; -import net.minecraft.world.level.biome.FixedBiomeSource; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkGenerator; -import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.FlatLevelSource; -import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; -import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; -import net.minecraft.world.level.levelgen.WorldOptions; -import net.minecraft.world.level.levelgen.blending.BlendingData; -import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; -import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; -import net.minecraft.world.level.storage.LevelStorageSource; -import net.minecraft.world.level.storage.PrimaryLevelData; -import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_19_R2.CraftServer; -import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R2.generator.CustomChunkGenerator; -import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; - -import javax.annotation.Nullable; -import java.lang.reflect.Field; -import java.nio.file.Path; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.OptionalLong; -import java.util.Random; -import java.util.concurrent.CompletableFuture; -import java.util.function.BooleanSupplier; -import java.util.function.Supplier; - -import static net.minecraft.core.registries.Registries.BIOME; - -public class PaperweightRegen extends Regenerator { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private static final Field serverWorldsField; - private static final Field paperConfigField; - private static final Field flatBedrockField; - private static final Field generatorSettingFlatField; - private static final Field generatorSettingBaseSupplierField; - private static final Field delegateField; - private static final Field chunkSourceField; - private static final Field generatorStructureStateField; - private static final Field ringPositionsField; - private static final Field hasGeneratedPositionsField; - - //list of chunk stati in correct order without FULL - private static final Map chunkStati = new LinkedHashMap<>(); - - static { - chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing - chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps - chunkStati.put( - ChunkStatus.STRUCTURE_REFERENCES, - Concurrency.FULL - ); // structure refs: radius 8, but only writes to current chunk - chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // biomes: radius 0 - chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8 - chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE - chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results - chunkStati.put( - ChunkStatus.LIQUID_CARVERS, - Concurrency.NONE - ); // liquid carvers: radius 0, but RADIUS and FULL change results - chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps - chunkStati.put( - ChunkStatus.LIGHT, - Concurrency.FULL - ); // light: radius 1, but no writes to other chunks, only current chunk - chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0 - chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0 - - try { - serverWorldsField = CraftServer.class.getDeclaredField("worlds"); - serverWorldsField.setAccessible(true); - - Field tmpPaperConfigField; - Field tmpFlatBedrockField; - try { //only present on paper - tmpPaperConfigField = Level.class.getDeclaredField("paperConfig"); - tmpPaperConfigField.setAccessible(true); - - tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock"); - tmpFlatBedrockField.setAccessible(true); - } catch (Exception e) { - tmpPaperConfigField = null; - tmpFlatBedrockField = null; - } - paperConfigField = tmpPaperConfigField; - flatBedrockField = tmpFlatBedrockField; - - generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName( - "settings", "e")); - generatorSettingBaseSupplierField.setAccessible(true); - - generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "d")); - generatorSettingFlatField.setAccessible(true); - - delegateField = CustomChunkGenerator.class.getDeclaredField("delegate"); - delegateField.setAccessible(true); - - chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "L")); - chunkSourceField.setAccessible(true); - - generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "w")); - generatorStructureStateField.setAccessible(true); - - ringPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(Refraction.pickName("ringPositions", "g")); - ringPositionsField.setAccessible(true); - - hasGeneratedPositionsField = ChunkGeneratorStructureState.class.getDeclaredField( - Refraction.pickName("hasGeneratedPositions", "h") - ); - hasGeneratedPositionsField.setAccessible(true); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - //runtime - private ServerLevel originalServerWorld; - private ServerChunkCache originalChunkProvider; - private ServerLevel freshWorld; - private ServerChunkCache freshChunkProvider; - private LevelStorageSource.LevelStorageAccess session; - private StructureTemplateManager structureTemplateManager; - private ThreadedLevelLightEngine threadedLevelLightEngine; - private ChunkGenerator chunkGenerator; - - private Path tempDir; - - private boolean generateFlatBedrock = false; - - public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) { - super(originalBukkitWorld, region, target, options); - } - - @Override - protected boolean prepare() { - this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle(); - originalChunkProvider = originalServerWorld.getChunkSource(); - if (!(originalChunkProvider instanceof ServerChunkCache)) { - return false; - } - - //flat bedrock? (only on paper) - if (paperConfigField != null) { - try { - generateFlatBedrock = flatBedrockField.getBoolean(paperConfigField.get(originalServerWorld)); - } catch (Exception ignored) { - } - } - - seed = options.getSeed().orElse(originalServerWorld.getSeed()); - chunkStati.forEach((s, c) -> super.chunkStati.put(new ChunkStatusWrap(s), c)); - - return true; - } - - @Override - @SuppressWarnings("unchecked") - protected boolean initNewWorld() throws Exception { - //world folder - tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen"); - - //prepare for world init (see upstream implementation for reference) - org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment(); - org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator(); - LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir); - ResourceKey levelStemResourceKey = getWorldDimKey(environment); - session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey); - PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData; - - MinecraftServer server = originalServerWorld.getCraftServer().getServer(); - WorldOptions originalOpts = originalWorldData.worldGenOptions(); - WorldOptions newOpts = options.getSeed().isPresent() - ? originalOpts.withSeed(OptionalLong.of(seed)) - : originalOpts; - LevelSettings newWorldSettings = new LevelSettings( - "faweregentempworld", - originalWorldData.settings.gameType(), - originalWorldData.settings.hardcore(), - originalWorldData.settings.difficulty(), - originalWorldData.settings.allowCommands(), - originalWorldData.settings.gameRules(), - originalWorldData.settings.getDataConfiguration() - ); - - PrimaryLevelData.SpecialWorldProperty specialWorldProperty = - originalWorldData.isFlatWorld() - ? PrimaryLevelData.SpecialWorldProperty.FLAT - : originalWorldData.isDebugWorld() - ? PrimaryLevelData.SpecialWorldProperty.DEBUG - : PrimaryLevelData.SpecialWorldProperty.NONE; - PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable()); - - BiomeProvider biomeProvider = getBiomeProvider(); - - - //init world - freshWorld = Fawe.instance().getQueueHandler().sync((Supplier) () -> new ServerLevel( - server, - server.executor, - session, - newWorldData, - originalServerWorld.dimension(), - DedicatedServer.getServer().registryAccess().registry(Registries.LEVEL_STEM).orElseThrow() - .getOrThrow(levelStemResourceKey), - new RegenNoOpWorldLoadListener(), - originalServerWorld.isDebug(), - seed, - ImmutableList.of(), - false, - environment, - generator, - biomeProvider - ) { - - private final Holder singleBiome = options.hasBiomeType() ? DedicatedServer.getServer().registryAccess() - .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( - WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) - ) : null; - - @Override - public void tick(BooleanSupplier shouldKeepTicking) { //no ticking - } - - @Override - public Holder getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { - if (options.hasBiomeType()) { - return singleBiome; - } - return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome( - biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler() - ); - } - }).get(); - freshWorld.noSave = true; - removeWorldFromWorldsMap(); - newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name - if (paperConfigField != null) { - paperConfigField.set(freshWorld, originalServerWorld.paperConfig()); - } - - ChunkGenerator originalGenerator = originalChunkProvider.getGenerator(); - if (originalGenerator instanceof FlatLevelSource flatLevelSource) { - FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings(); - chunkGenerator = new FlatLevelSource(generatorSettingFlat); - } else if (originalGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) { - Holder generatorSettingBaseSupplier = (Holder) generatorSettingBaseSupplierField.get( - originalGenerator); - BiomeSource biomeSource; - if (options.hasBiomeType()) { - - biomeSource = new FixedBiomeSource( - DedicatedServer.getServer().registryAccess() - .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( - WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) - ) - ); - } else { - biomeSource = originalGenerator.getBiomeSource(); - } - chunkGenerator = new NoiseBasedChunkGenerator( - biomeSource, - generatorSettingBaseSupplier - ); - } else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) { - chunkGenerator = customChunkGenerator.getDelegate(); - } else { - LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName()); - return false; - } - if (generator != null) { - chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator); - generateConcurrent = generator.isParallelCapable(); - } -// chunkGenerator.conf = freshWorld.spigotConfig; - Does not exist anymore, may need to be re-addressed - - freshChunkProvider = new ServerChunkCache( - freshWorld, - session, - server.getFixerUpper(), - server.getStructureManager(), - server.executor, - chunkGenerator, - freshWorld.spigotConfig.viewDistance, - freshWorld.spigotConfig.simulationDistance, - server.forceSynchronousWrites(), - new RegenNoOpWorldLoadListener(), - (chunkCoordIntPair, state) -> { - }, - () -> server.overworld().getDataStorage() - ) { - // redirect to LevelChunks created in #createChunks - @Override - public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean create) { - ChunkAccess chunkAccess = getChunkAt(x, z); - if (chunkAccess == null && create) { - chunkAccess = createChunk(getProtoChunkAt(x, z)); - } - return chunkAccess; - } - }; - - if (seed == originalOpts.seed() && !options.hasBiomeType()) { - // Optimisation for needless ring position calculation when the seed and biome is the same. - ChunkGeneratorStructureState state = (ChunkGeneratorStructureState) generatorStructureStateField.get(originalChunkProvider.chunkMap); - boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(state); - if (hasGeneratedPositions) { - Map>> origPositions = - (Map>>) ringPositionsField.get(state); - Map>> copy = new Object2ObjectArrayMap<>( - origPositions); - ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get(freshChunkProvider.chunkMap); - ringPositionsField.set(newState, copy); - hasGeneratedPositionsField.setBoolean(newState, true); - } - } - - - ReflectionUtils.unsafeSet(chunkSourceField, freshWorld, freshChunkProvider); - //let's start then - structureTemplateManager = server.getStructureManager(); - threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider); - - return true; - } - - @Override - protected void cleanup() { - try { - session.close(); - } catch (Exception ignored) { - } - - //shutdown chunk provider - try { - Fawe.instance().getQueueHandler().sync(() -> { - try { - freshChunkProvider.close(false); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - } catch (Exception ignored) { - } - - //remove world from server - try { - Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap); - } catch (Exception ignored) { - } - - //delete directory - try { - SafeFiles.tryHardToDeleteDir(tempDir); - } catch (Exception ignored) { - } - } - - @Override - protected ProtoChunk createProtoChunk(int x, int z) { - return new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld, - this.freshWorld.registryAccess().registryOrThrow(BIOME), null - ); - } - - @Override - protected LevelChunk createChunk(ProtoChunk protoChunk) { - return new LevelChunk( - freshWorld, - protoChunk, - null // we don't want to add entities - ); - } - - @Override - protected ChunkStatusWrap getFullChunkStatus() { - return new ChunkStatusWrap(ChunkStatus.FULL); - } - - @Override - protected List getBlockPopulators() { - return originalServerWorld.getWorld().getPopulators(); - } - - @Override - protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) { - // BlockPopulator#populate has to be called synchronously for TileEntity access - TaskManager.taskManager().task(() -> blockPopulator.populate(freshWorld.getWorld(), random, levelChunk.getBukkitChunk())); - } - - @Override - protected IChunkCache initSourceQueueCache() { - return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) { - @Override - public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) { - return getChunkAt(x, z); - } - }; - } - - //util - @SuppressWarnings("unchecked") - private void removeWorldFromWorldsMap() { - Fawe.instance().getQueueHandler().sync(() -> { - try { - Map map = (Map) serverWorldsField.get(Bukkit.getServer()); - map.remove("faweregentempworld"); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - }); - } - - private ResourceKey getWorldDimKey(org.bukkit.World.Environment env) { - return switch (env) { - case NETHER -> LevelStem.NETHER; - case THE_END -> LevelStem.END; - default -> LevelStem.OVERWORLD; - }; - } - - private static class RegenNoOpWorldLoadListener implements ChunkProgressListener { - - private RegenNoOpWorldLoadListener() { - } - - @Override - public void updateSpawnPos(ChunkPos spawnPos) { - } - - @Override - public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) { - } - - @Override - public void start() { - - } - - @Override - public void stop() { - } - - // TODO Paper only(?) @Override - public void setChunkRadius(int radius) { - } - - } - - private class FastProtoChunk extends ProtoChunk { - - public FastProtoChunk( - final ChunkPos pos, - final UpgradeData upgradeData, - final LevelHeightAccessor world, - final Registry biomeRegistry, - @Nullable final BlendingData blendingData - ) { - super(pos, upgradeData, world, biomeRegistry, blendingData); - } - - // avoid warning on paper - - // compatibility with spigot - - public boolean generateFlatBedrock() { - return generateFlatBedrock; - } - - // no one will ever see the entities! - @Override - public List getEntities() { - return Collections.emptyList(); - } - - } - - protected class ChunkStatusWrap extends ChunkStatusWrapper { - - private final ChunkStatus chunkStatus; - - public ChunkStatusWrap(ChunkStatus chunkStatus) { - this.chunkStatus = chunkStatus; - } - - @Override - public int requiredNeighborChunkRadius() { - return chunkStatus.getRange(); - } - - @Override - public String name() { - return chunkStatus.getName(); - } - - @Override - public CompletableFuture processChunk(Long xz, List accessibleChunks) { - return chunkStatus.generate( - Runnable::run, // TODO revisit, we might profit from this somehow? - freshWorld, - chunkGenerator, - structureTemplateManager, - threadedLevelLightEngine, - c -> CompletableFuture.completedFuture(Either.left(c)), - accessibleChunks, - true - ); - } - - } - - /** - * A light engine that does nothing. As light is calculated after pasting anyway, we can avoid - * work this way. - */ - static class NoOpLightEngine extends ThreadedLevelLightEngine { - - private static final ProcessorMailbox MAILBOX = ProcessorMailbox.create(task -> { - }, "fawe-no-op"); - private static final ProcessorHandle> HANDLE = ProcessorHandle.of("fawe-no-op", m -> { - }); - - public NoOpLightEngine(final ServerChunkCache chunkProvider) { - super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE); - } - - @Override - public CompletableFuture retainData(final ChunkAccess chunk) { - return CompletableFuture.completedFuture(chunk); - } - - @Override - public CompletableFuture lightChunk(final ChunkAccess chunk, final boolean excludeBlocks) { - return CompletableFuture.completedFuture(chunk); - } - - } - -}